<!DOCTYPE html>
<html lang="en-US" dir="ltr">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>MySQL索引 | VitePress</title>
    <meta name="description" content="A VitePress site">
    <link rel="preload stylesheet" href="/notebook/assets/style.3dbfd0c2.css" as="style">
    
    <script type="module" src="/notebook/assets/app.8aaa4cbe.js"></script>
    <link rel="preload" href="/notebook/assets/inter-roman-latin.2ed14f66.woff2" as="font" type="font/woff2" crossorigin="">
    <link rel="modulepreload" href="/notebook/assets/chunks/framework.1336c4e5.js">
    <link rel="modulepreload" href="/notebook/assets/chunks/theme.20cddc0c.js">
    <link rel="modulepreload" href="/notebook/assets/2、数据库_MySQL_MySQL面试_进阶.md.f934806d.lean.js">
    <script id="check-dark-light">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
  </head>
  <body>
    <div id="app"><div class="Layout" data-v-255ec12d><!--[--><!--]--><!--[--><span tabindex="-1" data-v-ae3e3f51></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-ae3e3f51> Skip to content </a><!--]--><!----><header class="VPNav" data-v-255ec12d data-v-7e5bc4a5><div class="VPNavBar has-sidebar" data-v-7e5bc4a5 data-v-0937f67c><div class="container" data-v-0937f67c><div class="title" data-v-0937f67c><div class="VPNavBarTitle has-sidebar" data-v-0937f67c data-v-86d1bed8><a class="title" href="/notebook/" data-v-86d1bed8><!--[--><!--]--><!--[--><img class="VPImage logo" src="/notebook/Vue.png" alt data-v-8426fc1a><!--]--><!--[-->任硕的文档<!--]--><!--[--><!--]--></a></div></div><div class="content" data-v-0937f67c><div class="curtain" data-v-0937f67c></div><div class="content-body" data-v-0937f67c><!--[--><!--]--><div class="VPNavBarSearch search" style="--vp-meta-key:&#39;Meta&#39;;" data-v-0937f67c><!--[--><!----><div id="docsearch"><button type="button" class="DocSearch DocSearch-Button" aria-label="Search"><span class="DocSearch-Button-Container"><svg class="DocSearch-Search-Icon" width="20" height="20" viewBox="0 0 20 20" aria-label="search icon"><path d="M14.386 14.386l4.0877 4.0877-4.0877-4.0877c-2.9418 2.9419-7.7115 2.9419-10.6533 0-2.9419-2.9418-2.9419-7.7115 0-10.6533 2.9418-2.9419 7.7115-2.9419 10.6533 0 2.9419 2.9418 2.9419 7.7115 0 10.6533z" stroke="currentColor" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round"></path></svg><span class="DocSearch-Button-Placeholder">Search</span></span><span class="DocSearch-Button-Keys"><kbd class="DocSearch-Button-Key"></kbd><kbd class="DocSearch-Button-Key">K</kbd></span></button></div><!--]--></div><nav aria-labelledby="main-nav-aria-label" class="VPNavBarMenu menu" data-v-0937f67c data-v-7f418b0f><span id="main-nav-aria-label" class="visually-hidden" data-v-7f418b0f>Main Navigation</span><!--[--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>Java学前端</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/HTML+JS.html" data-v-2f2cfafc><!--[-->HTML+JS<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/CSS.html" data-v-2f2cfafc><!--[-->CSS<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/Vue2+%E7%BB%84%E4%BB%B6.html" data-v-2f2cfafc><!--[-->Vue2+组件<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/Vue3+%E7%BB%84%E4%BB%B6.html" data-v-2f2cfafc><!--[-->Vue3+组件<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/Java%E5%AD%A6%E5%89%8D%E7%AB%AF/React.html" data-v-2f2cfafc><!--[-->React<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>软件测试</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95/%E6%B5%8B%E8%AF%95%E5%9F%BA%E7%A1%80.html" data-v-2f2cfafc><!--[-->测试基础<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%95/%E5%8E%8B%E5%8A%9B%E6%B5%8B%E8%AF%95.html" data-v-2f2cfafc><!--[-->压力测试<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>多线程</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E5%B9%B6%E5%8F%91%20&amp;%20%E5%A4%9A%E7%BA%BF%E7%A8%8B/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-2f2cfafc><!--[-->基础篇<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E5%B9%B6%E5%8F%91%20&amp;%20%E5%A4%9A%E7%BA%BF%E7%A8%8B/%E5%B9%B6%E5%8F%91%E5%AE%8C%E5%96%84.html" data-v-2f2cfafc><!--[-->进阶篇<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>开发工具</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/IDEA/Chrome.html" data-v-2f2cfafc><!--[-->Chrome<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/IDEA/IDEA%E5%9F%BA%E7%A1%80.html" data-v-2f2cfafc><!--[-->IDEA基础<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/IDEA/IDEA%E6%8F%92%E4%BB%B6.html" data-v-2f2cfafc><!--[-->IDEA插件<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/IDEA/VS%20Code.html" data-v-2f2cfafc><!--[-->VS Code<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-7f418b0f data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-a7b5672a><span class="text" data-v-a7b5672a><!----><span data-v-a7b5672a>消息中间件</span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-a7b5672a><path d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z"></path></svg></span></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><div class="items" data-v-e7ea1737><!--[--><!--[--><div class="VPMenuGroup" data-v-e7ea1737 data-v-69e747b5><!----><!--[--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/RabbitMQ.html" data-v-2f2cfafc><!--[-->RabbitMQ<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/RocketMQ.html" data-v-2f2cfafc><!--[-->RocketMQ<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/Kafka.html" data-v-2f2cfafc><!--[-->Kafka<!--]--></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-69e747b5 data-v-2f2cfafc><a class="VPLink link" href="/notebook/%E6%B6%88%E6%81%AF%E4%B8%AD%E9%97%B4%E4%BB%B6/Canal.html" data-v-2f2cfafc><!--[-->Canal<!--]--></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-0937f67c data-v-f6a63727><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="toggle dark mode" aria-checked="false" data-v-f6a63727 data-v-82b282f1 data-v-f3c41672><span class="check" data-v-f3c41672><span class="icon" data-v-f3c41672><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-82b282f1><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-82b282f1><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div><div class="VPSocialLinks VPNavBarSocialLinks social-links" data-v-0937f67c data-v-0394ad82 data-v-7bc22406><!--[--><a class="VPSocialLink no-icon" href="https://github.com/renshuo123/renshuo123.github.io" aria-label="github" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><a class="VPSocialLink no-icon" href="#" aria-label="twitter" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Twitter</title><path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"/></svg></a><a class="VPSocialLink no-icon" href="https://github.com/" aria-label target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg t="1676028692954" class="icon" ...</path></svg></a><!--]--></div><div class="VPFlyout VPNavBarExtra extra" data-v-0937f67c data-v-40855f84 data-v-a7b5672a><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-a7b5672a><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="icon" data-v-a7b5672a><circle cx="12" cy="12" r="2"></circle><circle cx="19" cy="12" r="2"></circle><circle cx="5" cy="12" r="2"></circle></svg></button><div class="menu" data-v-a7b5672a><div class="VPMenu" data-v-a7b5672a data-v-e7ea1737><!----><!--[--><!--[--><!----><div class="group" data-v-40855f84><div class="item appearance" data-v-40855f84><p class="label" data-v-40855f84>Appearance</p><div class="appearance-action" data-v-40855f84><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" title="toggle dark mode" aria-checked="false" data-v-40855f84 data-v-82b282f1 data-v-f3c41672><span class="check" data-v-f3c41672><span class="icon" data-v-f3c41672><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-82b282f1><path d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z"></path><path d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z"></path><path d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z"></path><path d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z"></path><path d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z"></path><path d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z"></path><path d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z"></path><path d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z"></path><path d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="moon" data-v-82b282f1><path d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z"></path></svg><!--]--></span></span></button></div></div></div><div class="group" data-v-40855f84><div class="item social-links" data-v-40855f84><div class="VPSocialLinks social-links-list" data-v-40855f84 data-v-7bc22406><!--[--><a class="VPSocialLink no-icon" href="https://github.com/renshuo123/renshuo123.github.io" aria-label="github" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a><a class="VPSocialLink no-icon" href="#" aria-label="twitter" target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Twitter</title><path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"/></svg></a><a class="VPSocialLink no-icon" href="https://github.com/" aria-label target="_blank" rel="noopener" data-v-7bc22406 data-v-f80f8133><svg t="1676028692954" class="icon" ...</path></svg></a><!--]--></div></div></div><!--]--><!--]--></div></div></div><!--[--><!--]--><button type="button" class="VPNavBarHamburger hamburger" aria-label="mobile navigation" aria-expanded="false" aria-controls="VPNavScreen" data-v-0937f67c data-v-e5dd9c1c><span class="container" data-v-e5dd9c1c><span class="top" data-v-e5dd9c1c></span><span class="middle" data-v-e5dd9c1c></span><span class="bottom" data-v-e5dd9c1c></span></span></button></div></div></div></div><!----></header><div class="VPLocalNav reached-top" data-v-255ec12d data-v-5cfd5582><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-5cfd5582><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="menu-icon" data-v-5cfd5582><path d="M17,11H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,11,17,11z"></path><path d="M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z"></path><path d="M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z"></path><path d="M17,19H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,19,17,19z"></path></svg><span class="menu-text" data-v-5cfd5582>Menu</span></button><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-5cfd5582 data-v-18201f51><button data-v-18201f51>Return to top</button><!----></div></div><aside class="VPSidebar" data-v-255ec12d data-v-845b8fc6><div class="curtain" data-v-845b8fc6></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-845b8fc6><span class="visually-hidden" id="sidebar-aria-label" data-v-845b8fc6> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Java</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E6%96%B0%E7%89%B9%E6%80%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java新特性</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E9%9B%86%E5%90%88.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java集合</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Java/Java%E9%AB%98%E7%BA%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Java高级</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Linux</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/Linux%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Linux基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/Linux%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Linux新特性</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/Shell.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Shell脚本</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/%E5%AE%9E%E7%94%A8%E8%84%9A%E6%9C%AC.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>实用脚本</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Linux/%E8%BD%AF%E4%BB%B6%E9%83%A8%E7%BD%B2.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>软件部署</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Nginx</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Nginx/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Nginx/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Nginx/%E5%AE%9E%E6%88%98%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>实战篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Nginx/%E9%9D%A2%E8%AF%95%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>面试篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>SSM</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/SSM/Maven.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Maven</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/SSM/Spring.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Spring</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/SSM/SpringMVC.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringMVC</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/SSM/SpringBatch.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringBatch</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>SpringBoot</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/3%E3%80%81SpringBoot/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/3%E3%80%81SpringBoot/%E5%BA%94%E7%94%A8%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>应用篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/3%E3%80%81SpringBoot/%E6%96%B0%E7%89%B9%E6%80%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>新特性</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/3%E3%80%81SpringBoot/%E8%BF%90%E7%BB%B4&amp;%E5%8E%9F%E7%90%86.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>运维&原理</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>SpringCloud</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringCloud</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/%E5%BF%85%E5%A4%87/Sentinel.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Sentinel</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>SpringSecurity</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/SpringSecurity/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringSecurity基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/SpringSecurity/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringSecurity进阶篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/SpringSecurity/%E9%AB%98%E7%BA%A7%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>SpringSecurity高级篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Mybatis & MybatisPlus</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Mybatis&amp;MybatisPlus/Mybatis.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Mybatis</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Mybatis&amp;MybatisPlus/MybatisPlus.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MybatisPlus</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/Mybatis&amp;MybatisPlus/JPA.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>JPA</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>Git & ChatGPT</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/Git.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Git</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/Github.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Github</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/ChatGPT.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ChatGPT</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/Jenkins.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Jenkins</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/5%E3%80%81%E8%BF%90%E7%BB%B4/Netty.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Netty</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>数据库</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>MySQL</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E4%BC%98%E5%8C%96.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL优化</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E8%AE%BE%E8%AE%A1.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL设计</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/MySQL%E6%A0%B8%E5%BF%83/%E8%BF%90%E7%BB%B4.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MySQL运维</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MySQL/%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>分库分表</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>Redis</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E4%BC%98%E5%8C%96.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis优化</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E5%8E%9F%E7%90%86.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis原理</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E9%AB%98%E7%BA%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis高级</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/Redis%E5%AE%9E%E6%88%98.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Redis实战</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Redis/%E6%9C%AC%E5%9C%B0%E7%BC%93%E5%AD%98.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>本地缓存</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>MongoDB</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MongoDB/%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MongoDB基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/MongoDB/%E6%95%B4%E5%90%88.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>MongoDB进阶</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>ElasticSearch</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/ElasticSearch/1%E3%80%81ES%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ES基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/ElasticSearch/3%E3%80%81ES%E9%AB%98%E7%BA%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ES高级</p><!--]--></a><!----></div><!----></div><!--]--></div></section><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/influxdb.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>InfluxDB</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93/Neo4j.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Neo4j</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>高并发 & 秒杀 & 分布式</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%B8%89%E9%AB%98/%E5%88%86%E5%B8%83%E5%BC%8F.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>分布式理论</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/4%E3%80%81%E5%BE%AE%E6%9C%8D%E5%8A%A1/%E5%BF%85%E5%A4%87/%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>分布式锁</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%B8%89%E9%AB%98/%E7%A7%92%E6%9D%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>秒杀</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%B8%89%E9%AB%98/%E9%AB%98%E5%8F%AF%E7%94%A8.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>高可用</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%B8%89%E9%AB%98/%E9%AB%98%E5%B9%B6%E5%8F%91.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>高并发</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>云原生</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%BA%91%E5%8E%9F%E7%94%9F/Docker.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Docker</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E4%BA%91%E5%8E%9F%E7%94%9F/K8S.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>K8S</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>可视化 & 监控</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E5%8F%AF%E8%A7%86%E5%8C%96%20&amp;%20%E7%9B%91%E6%8E%A7/%E7%9B%91%E6%8E%A7%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>监控基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E5%8F%AF%E8%A7%86%E5%8C%96%20&amp;%20%E7%9B%91%E6%8E%A7/%E7%9B%91%E6%8E%A7%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>监控进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E5%8F%AF%E8%A7%86%E5%8C%96%20&amp;%20%E7%9B%91%E6%8E%A7/%E5%8F%AF%E8%A7%86%E5%8C%96%E5%A4%A7%E5%B1%8F.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>可视化大屏</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E5%8F%AF%E8%A7%86%E5%8C%96%20&amp;%20%E7%9B%91%E6%8E%A7/Zabbix.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Zabbix</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>学前端</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>HTML+CSS</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/1%E3%80%81HTML+CSS/HTML%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>HTML基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/1%E3%80%81HTML+CSS/CSS%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>CSS基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/1%E3%80%81HTML+CSS/%E7%BD%91%E9%A1%B5%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>网页进阶</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>JS+TS</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/JS%20%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>JS基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/JS%20%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>JS进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/ES6%20%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ES6基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/ES6%20%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>ES6进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/2%E3%80%81JS+TS/TypeScript.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>TS基础</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>NodeJS</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/4%E3%80%81Node/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Node基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/4%E3%80%81Node/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Node进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/4%E3%80%81Node/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>项目实战</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>Vue</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/3%E3%80%81Vue/Vue3/Vue3%E8%BF%9B%E9%98%B6.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Vue3进阶</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/3%E3%80%81Vue/Vue3/Vue3%E9%AB%98%E7%BA%A7.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Vue3高级</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/3%E3%80%81Vue/Vue3/Vue3%E6%96%B0%E8%AF%AD%E6%B3%95.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>Vue3新语法</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/3%E3%80%81Vue/Vue2/Vue2%E9%A1%B9%E7%9B%AE.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>项目实战</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>小程序</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/5%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>小程序基础</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/5%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F/%E5%B0%8F%E7%A8%8B%E5%BA%8F%E4%BC%98%E5%8C%96.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>小程序优化</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/5%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F/uniapp.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>uniapp</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/1%E3%80%81%E5%AD%A6%E5%89%8D%E7%AB%AF/5%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F/%E5%B0%8F%E7%A8%8B%E5%BA%8F%E9%A1%B9%E7%9B%AE.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>项目实战</p><!--]--></a><!----></div><!----></div><!--]--></div></section><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>计算机基础</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>数据结构</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>操作系统</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>设计模式</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E5%9F%BA%E7%A1%80.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>计算机网络</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/UML.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>UML</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E8%AE%A1%E7%AE%97%E6%9C%BA%E5%9F%BA%E7%A1%80/%E7%AE%97%E6%B3%95/LeetCode.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>LeetCode</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0 collapsible collapsed" data-v-845b8fc6 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h2 class="text" data-v-9b797284>项目实战</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>云尚办公</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E4%BA%91%E5%B0%9A%E5%8A%9E%E5%85%AC/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>小兔鲜</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E5%B0%8F%E5%85%94%E9%B2%9C/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E5%B0%8F%E5%85%94%E9%B2%9C/%E8%BF%9B%E9%98%B6%E7%AF%871.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇1</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E5%B0%8F%E5%85%94%E9%B2%9C/%E8%BF%9B%E9%98%B6%E7%AF%872.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇2</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>地图</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E7%99%BE%E5%BA%A6%E5%9C%B0%E5%9B%BE/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>苍穹外卖</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E8%8B%8D%E7%A9%B9%E5%A4%96%E5%8D%96/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section><section class="VPSidebarItem level-1 collapsible collapsed" data-v-9b797284 data-v-9b797284><div class="item" role="button" tabindex="0" data-v-9b797284><div class="indicator" data-v-9b797284></div><h3 class="text" data-v-9b797284>黑马头条</h3><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-9b797284><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-9b797284><path d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z"></path></svg></div></div><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%BB%91%E9%A9%AC%E5%A4%B4%E6%9D%A1/%E5%9F%BA%E7%A1%80%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>基础篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%BB%91%E9%A9%AC%E5%A4%B4%E6%9D%A1/%E8%BF%9B%E9%98%B6%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%BB%91%E9%A9%AC%E5%A4%B4%E6%9D%A1/%E8%BF%9B%E9%98%B6%E7%AF%872.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>进阶篇2</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-2 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%BB%91%E9%A9%AC%E5%A4%B4%E6%9D%A1/%E9%AB%98%E7%BA%A7%E7%AF%87.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>高级篇</p><!--]--></a><!----></div><!----></div><!--]--></div></section><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E6%94%AF%E4%BB%98.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>支付</p><!--]--></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/%E9%A1%B9%E7%9B%AE%E5%AE%9E%E6%88%98/%E9%A1%B9%E7%9B%AE%E6%8E%A8%E8%8D%90.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>项目推荐</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-845b8fc6><section class="VPSidebarItem level-0" data-v-845b8fc6 data-v-9b797284><!----><div class="items" data-v-9b797284><!--[--><div class="VPSidebarItem level-1 is-link" data-v-9b797284 data-v-9b797284><div class="item" data-v-9b797284><div class="indicator" data-v-9b797284></div><a class="VPLink link link" href="/notebook/team.html" data-v-9b797284><!--[--><p class="text" data-v-9b797284>团队成员</p><!--]--></a><!----></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-255ec12d data-v-669faec9><div class="VPDoc has-sidebar has-aside" data-v-669faec9 data-v-6b87e69f><!--[--><!--]--><div class="container" data-v-6b87e69f><div class="aside" data-v-6b87e69f><div class="aside-curtain" data-v-6b87e69f></div><div class="aside-container" data-v-6b87e69f><div class="aside-content" data-v-6b87e69f><div class="VPDocAside" data-v-6b87e69f data-v-3f215769><!--[--><!--]--><!--[--><!--]--><div class="VPDocAsideOutline" data-v-3f215769 data-v-ff0f39c8><div class="content" data-v-ff0f39c8><div class="outline-marker" data-v-ff0f39c8></div><div class="outline-title" data-v-ff0f39c8>On this page</div><nav aria-labelledby="doc-outline-aria-label" data-v-ff0f39c8><span class="visually-hidden" id="doc-outline-aria-label" data-v-ff0f39c8> Table of Contents for current page </span><ul class="root" data-v-ff0f39c8 data-v-d0ee3533><!--[--><!--]--></ul></nav></div></div><!--[--><!--]--><div class="spacer" data-v-3f215769></div><!--[--><!--]--><!----><!--[--><!--]--><!--[--><!--]--></div></div></div></div><div class="content" data-v-6b87e69f><div class="content-container" data-v-6b87e69f><!--[--><!--]--><!----><main class="main" data-v-6b87e69f><div style="position:relative;" class="vp-doc _notebook_2%E3%80%81%E6%95%B0%E6%8D%AE%E5%BA%93_MySQL_MySQL%E9%9D%A2%E8%AF%95_%E8%BF%9B%E9%98%B6" data-v-6b87e69f><div><h1 id="mysql索引" tabindex="-1">MySQL索引 <a class="header-anchor" href="#mysql索引" aria-label="Permalink to &quot;MySQL索引&quot;">​</a></h1><h2 id="mysql如何实现的索引机制" tabindex="-1">MySQL如何实现的索引机制 <a class="header-anchor" href="#mysql如何实现的索引机制" aria-label="Permalink to &quot;MySQL如何实现的索引机制&quot;">​</a></h2><blockquote><p>MySQL中索引分三类：B+树索引、Hash索引、全文索引</p></blockquote><h2 id="innodb索引与myisam索引实现的区别" tabindex="-1">InnoDB索引与MyISAM索引实现的区别 <a class="header-anchor" href="#innodb索引与myisam索引实现的区别" aria-label="Permalink to &quot;InnoDB索引与MyISAM索引实现的区别&quot;">​</a></h2><blockquote><p>MyISAM的索引方式都是非聚簇的，与InnoDB包含1个聚簇索引是不同的。</p></blockquote><blockquote><p>在InnoDB存储引擎中，我们只需要根据主键值对聚簇索引进行一次查找就能找到对应的记录，而在MyISAM中却需要进行一次回表操作，意味着MyISAM中建立的索引相当于全部都是二级索引 。</p></blockquote><blockquote><p>InnoDB的数据文件本身就是索引文件，而MyISAM索引文件和数据文件是分离的 ，索引文件仅保存数据记录的地址。</p></blockquote><ul><li>MyISAM的表在磁盘上存储在以下文件中： <code>*.sdi（描述表结构）</code>、<code>*.MYD（数据）</code>，<code>*.MYI（索引）</code></li><li>InnoDB的表在磁盘上存储在以下文件中： <code>.ibd（表结构、索引和数据都存在一起）</code></li></ul><blockquote><p>InnoDB的非聚簇索引data域存储相应记录主键的值 ，而MyISAM索引记录的是地址 。换句话说，InnoDB的所有非聚簇索引都引用主键作为data域。</p></blockquote><blockquote><p>MyISAM的回表操作是十分快速的，因为是拿着地址偏移量直接到文件中取数据的，反观InnoDB是通过获取主键之后再去聚簇索引里找记录，虽然说也不慢，但还是比不上直接用地址去访问。</p></blockquote><blockquote><p>InnoDB要求表必须有主键 （ MyISAM可以没有 ）。如果没有显式指定，则MySQL系统会自动选择一个可以非空且唯一标识数据记录的列作为主键。如果不存在这种列，则MySQL自动为InnoDB表生成一个隐含字段作为主键，这个字段长度为6个字节，类型为长整型。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059814.png" alt="image-20220709183820796" style="zoom:80%;"><h2 id="一个表中如果没有创建索引-那么还会创建b-树吗" tabindex="-1">一个表中如果没有创建索引，那么还会创建B+树吗 <a class="header-anchor" href="#一个表中如果没有创建索引-那么还会创建b-树吗" aria-label="Permalink to &quot;一个表中如果没有创建索引，那么还会创建B+树吗&quot;">​</a></h2><blockquote><ul><li><p>如果有主键会创建聚簇索引</p></li><li><p>如果没有主键会生成rowid作为隐式主键</p></li></ul></blockquote><h2 id="说一下b-树索引实现原理-数据结构" tabindex="-1">说一下B+树索引实现原理（数据结构） <a class="header-anchor" href="#说一下b-树索引实现原理-数据结构" aria-label="Permalink to &quot;说一下B+树索引实现原理（数据结构）&quot;">​</a></h2><p>假设有一个表index_demo，表中有2个INT类型的列，1个CHAR(1)类型的列，c1列为主键：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">CREATE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">TABLE</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">index_demo</span><span style="color:#A6ACCD;">(c1 </span><span style="color:#C792EA;">INT</span><span style="color:#A6ACCD;">,c2 </span><span style="color:#C792EA;">INT</span><span style="color:#A6ACCD;">,c3 </span><span style="color:#C792EA;">CHAR</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">),</span><span style="color:#C792EA;">PRIMARY KEY</span><span style="color:#A6ACCD;">(c1)) ;</span></span></code></pre></div><p>index_demo表的简化的行格式示意图如下：</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059837.png" alt="image-20220709071051043"></p><p>我们只在示意图里展示记录的这几个部分：</p><ul><li><code>record_type：</code>表示记录的类型， 0是普通记录、 2是最小记录、 3 是最大记录、1是B+树非叶子节点记录。</li><li><code>next_record：</code>表示下一条记录的相对位置，我们用箭头来表明下一条记录。</li><li><code>各个列的值：</code>这里只记录在 index_demo 表中的三个列，分别是 c1 、 c2 和 c3 。</li><li><code>其他信息：</code>除了上述3种信息以外的所有信息，包括其他隐藏列的值以及记录的额外信息。</li></ul><p>将<code>其他信息</code>项暂时去掉并把它竖起来的效果就是这样：</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059836.png" alt="image-20220709071958145"></p><p>把一些记录放到页里的示意图就是（这里一页就是一个磁盘块，代表一次IO）：</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059838.png" alt="image-20220709072138395"></p><p>name age sex</p><p><code>MySQL InnoDB的默认的页大小是16KB</code>，因此数据存储在磁盘中，可能会占用多个数据页。如果各个页中的记录没有规律，我们就不得不依次遍历所有的数据页。<code>如果我们想快速的定位到需要查找的记录在哪些数据页中</code>，我们可以这样做 ：</p><ul><li>下一个数据页中用户记录的主键值必须大于上一个页中用户记录的主键值</li><li>给所有的页建立目录项</li></ul><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059839.png" alt="image-20220709073749310"></p><p>以<code>页28</code>为例，它对应<code>目录项2</code> ，这个目录项中包含着该页的<code>页号28</code>以及该页中用户记录的<code>最小主键值 5</code>。我们只需要把几个目录项在物理存储器上连续存储（比如：数组），就可以实现根据主键值快速查找某条记录的功能了。<code>比如：查找主键值为 20 的记录，具体查找过程分两步：</code></p><ol><li>先从目录项中根据二分法快速确定出<code>主键值为20的记录在目录项3中</code>（因为 12 ≤ 20 &lt; 209 ），<code>对应页9</code>。</li><li>再到页9中根据二分法快速定位到主键值为 20 的用户记录。</li></ol><p>至此，针对数据页做的简易目录就搞定了。这个目录有一个别名，称为<code>索引</code> 。</p><h2 id="innodb中的索引方案" tabindex="-1">InnoDB中的索引方案 <a class="header-anchor" href="#innodb中的索引方案" aria-label="Permalink to &quot;InnoDB中的索引方案&quot;">​</a></h2><p>我们新分配一个编号为30的页来专门存储<code>目录项记录</code>，页10、28、9、20专门存储<code>用户记录</code>：</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059838.png" alt="image-20220709073749310"></p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059486.png" alt="img"></p><p><code>目录项记录和普通的用户记录的不同点：</code></p><ul><li>目录项记录 的 record_type 值是1，而 普通用户记录 的 record_type 值是0。</li><li>目录项记录只有主键值和页的编号两个列，而普通的用户记录的列是用户自己定义的，包含很多列，另外还有InnoDB自己添加的隐藏列。</li></ul><p><code>现在查找主键值为 20 的记录，具体查找过程分两步：</code></p><ol><li>先到页30中通过二分法快速定位到对应目录项，因为 12 ≤ 20 &lt; 209 ，就是页9。</li><li>再到页9中根据二分法快速定位到主键值为 20 的用户记录。</li></ol><p><strong>更复杂的情况如下：</strong></p><p>我们生成了一个存储更高级目录项的 页33 ，这个页中的两条记录分别代表页30和页32，如果用户记录的主键值在 <code>[1, 320)</code> 之间，则到页30中查找更详细的目录项记录，如果主键值 不小于320 的话，就到页32中查找更详细的目录项记录。<strong>这个数据结构，它的名称是 B+树 。</strong></p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059503.png" alt="image-20220709080648851"></p><h2 id="聚簇索引与非聚簇索引b-树实现有什么区别" tabindex="-1">聚簇索引与非聚簇索引b+树实现有什么区别 <a class="header-anchor" href="#聚簇索引与非聚簇索引b-树实现有什么区别" aria-label="Permalink to &quot;聚簇索引与非聚簇索引b+树实现有什么区别&quot;">​</a></h2><h3 id="聚簇索引" tabindex="-1">聚簇索引 <a class="header-anchor" href="#聚簇索引" aria-label="Permalink to &quot;聚簇索引&quot;">​</a></h3><p><strong>特点：</strong></p><ul><li><p><code>索引和数据保存在同一个B+树中</code></p></li><li><p><code>页内的记录</code>是按照<code>主键</code>的大小顺序排成一个<code>单向链表</code> 。</p></li><li><p><code>页和页之间</code>也是根据页中记录的<code>主键</code>的大小顺序排成一个<code>双向链表</code> 。</p></li><li><p>非叶子节点存储的是记录的<code>主键+页号</code>。</p></li><li><p>叶子节点存储的是<code>完整的用户记录</code>。</p></li></ul><p><strong>优点：</strong></p><ul><li>数据访问更快 ，因为<code>索引和数据保存在同一个B+树中</code>，因此从聚簇索引中获取数据比非聚簇索引更快。</li><li>聚簇索引对于主键的<code>排序查找</code>和<code>范围查找</code>速度非常快。</li><li>按照聚簇索引排列顺序，查询显示一定范围数据的时候，由于<code>数据都是紧密相连</code>，数据库可以从更少的数据块中提取数据，<code>节省了大量的IO操作</code> 。</li></ul><p><strong>缺点：</strong></p><ul><li>**插入速度严重依赖于插入顺序 ，按照主键的顺序插入是最快的方式，否则将会出现页分裂，严重影响性能。**因此，对于InnoDB表，我们一般都会定义一个<code>自增的ID列为主键</code>。</li><li>更新主键的代价很高 ，因为将会导致被更新的行移动。因此，对于InnoDB表，我们一般定义<code>主键为不可更新</code>。</li></ul><p><strong>限制：</strong></p><ul><li>只有InnoDB引擎支持聚簇索引，<code>MyISAM不支持聚簇索引</code>。</li><li>由于数据的物理存储排序方式只能有一种，所以<code>每个MySQL的表只能有一个聚簇索引</code>。</li><li>如果没有为表定义主键，InnoDB会选择<code>非空的唯一索引列代替</code>。如果没有这样的列，InnoDB会<code>隐式的定义一个主键</code>作为聚簇索引。</li><li>为了充分利用聚簇索引的聚簇特性，InnoDB中表的<code>主键应选择有序的id</code>，不建议使用无序的id，比如UUID、MD5、HASH、字符串作为主键，无法保证数据的顺序增长。</li></ul><h3 id="非聚簇索引" tabindex="-1">非聚簇索引 <a class="header-anchor" href="#非聚簇索引" aria-label="Permalink to &quot;非聚簇索引&quot;">​</a></h3><p><strong>（二级索引、辅助索引）</strong></p><p><code>聚簇索引</code>，只能在搜索条件是<code>主键值</code>时才发挥作用，因为B+树中的数据都是按照主键进行排序的，如果我们想以别的列作为搜索条件，那么需要创建<code>非聚簇索引</code>。</p><p><strong>例如，</strong><code>以c2列作为搜索条件</code>，那么需要使<code>用c2列创建一棵B+树</code>，如下所示：</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059519.png" alt="image-20220709130937991"></p><p><strong>这个B+树与聚簇索引有几处不同：</strong></p><ul><li><p><code>页内的记录</code>是按照从<code>c2列</code>的大小顺序排成一个<code>单向链表</code> 。</p></li><li><p><code>页和页之间</code>也是根据页中记录的<code>c2列</code>的大小顺序排成一个<code>双向链表</code> 。</p></li><li><p>非叶子节点存储的是记录的<code>c2列+页号</code>。</p></li><li><p>叶子节点存储的并不是完整的用户记录，而只是<code>c2列+主键</code>这两个列的值。</p></li></ul><p><strong>一张表可以有多个非聚簇索引：</strong></p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059536.png" alt="image-20220709134109900"></p><h2 id="b-树中聚簇索引的查找-匹配-逻辑" tabindex="-1">B+树中聚簇索引的查找（匹配）逻辑 <a class="header-anchor" href="#b-树中聚簇索引的查找-匹配-逻辑" aria-label="Permalink to &quot;B+树中聚簇索引的查找（匹配）逻辑&quot;">​</a></h2><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.1.30/202212311059365.png" alt="image-20221231105907237" style="zoom:80%;"><h2 id="b-树中非聚簇索引的查找-匹配-逻辑" tabindex="-1">B+树中非聚簇索引的查找（匹配）逻辑 <a class="header-anchor" href="#b-树中非聚簇索引的查找-匹配-逻辑" aria-label="Permalink to &quot;B+树中非聚簇索引的查找（匹配）逻辑&quot;">​</a></h2><p>**例如：**根据c2列的值查找c2=4的记录，查找过程如下：</p><ol><li>根据<code>根页面44</code>定位到<code>页42</code>（因为<code>2 ≤ 4 &lt; 9</code>）</li><li>由于<code>c2列没有唯一性约束</code>，所以c2=4的记录可能分布在多个数据页中，又因为 <code>2 ≤ 4 ≤ 4</code>，所以确定实际存储用户记录的页在<code>页34和页35</code>中。</li><li>在页34和35中<code>定位到具体的记录</code>。</li><li>但是这个B+树的叶子节点<code>只存储了c2和c1（主键）</code>两个列，所以我们必须<code>再根据主键值去聚簇索引中再查找</code>一遍完整的用户记录。</li><li>like 张%</li></ol><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059519.png" alt="image-20220709130937991"></p><h2 id="平衡二叉树-红黑树-b树和b-树的区别是什么-都有哪些应用场景" tabindex="-1">平衡二叉树，红黑树，B树和B+树的区别是什么？都有哪些应用场景？ <a class="header-anchor" href="#平衡二叉树-红黑树-b树和b-树的区别是什么-都有哪些应用场景" aria-label="Permalink to &quot;平衡二叉树，红黑树，B树和B+树的区别是什么？都有哪些应用场景？&quot;">​</a></h2><p>平衡二叉树</p><ul><li>基础数据结构</li><li>左右平衡</li><li>高度差大于1会自旋</li><li>每个节点记录一个数据</li></ul><p><strong>平衡二叉树（AVL）</strong></p><p>AVL树全称G.M. Adelson-Velsky和E.M. Landis，这是两个人的人名。</p><p>平衡二叉树也叫平衡二叉搜索树（Self-balancing binary search tree）又被称为AVL树， 可以保证查询效率较高。</p><p><code>具有以下特点：</code></p><ul><li>它是一棵空树或它的左右两个子树的高度差的绝对值不超过1</li><li>并且左右两个子树都是一棵平衡二叉树。</li></ul><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059557.png" alt="image-20220708235509010"></p><p>AVL的生成演示：<a href="https://www.cs.usfca.edu/~galles/visualization/AVLtree.html" target="_blank" rel="noreferrer">https://www.cs.usfca.edu/~galles/visualization/AVLtree.html</a></p><p><strong>AVL的问题</strong></p><p>众所周知，IO操作的效率很低，在大量数据存储中，查询时我们不能一下子将所有数据加载到内存中，只能逐节点加载（一个节点一次IO）。如果我们利用二叉树作为索引结构，<code>那么磁盘的IO次数和索引树的高度是相关的</code>。平衡二叉树由于树深度过大而造成磁盘IO读写过于频繁，进而导致效率低下。</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059574.png" alt="image-20220708233351509"></p><p>为了提高查询效率，就需要 减少磁盘IO数 。<code>为了减少磁盘IO的次数，就需要尽量降低树的高度</code> ，需要把原来“瘦高”的树结构变的“矮胖”，树的每层的分叉越多越好。针对同样的数据，如果我们把二叉树改成 三叉树：</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059095.png" alt="image-20220708235725124"></p><p>上面的例子中，我们将二叉树变成了三叉树，降低了树的高度。如果能够在一个节点中存放更多的数据，我们还可以进一步减少节点的数量，从而进一步降低树的高度。这就是<code>多叉树</code>。</p><p><strong>普通树的问题</strong></p><ul><li>左子树全部为空，从形式上看，更像一个单链表，不能发挥BST的优势。</li><li><code>解决方案：平衡二叉树(AVL)</code></li></ul><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059110.png" alt="image-20220708231622916"></p><p>红黑树</p><ul><li>hashmap存储</li><li>两次旋转达到平衡</li><li>分为红黑节点</li></ul><p>在这个棵严格的平台树上又进化为“红黑树”{是一个非严格的平衡树 左子树与右子树的高度差不能超过1}，红黑树的长子树只要不超过短子树的两倍即可！</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059126.png" alt="image-20221027154142690"></p><p>当再次插入7的时候，这棵树就会发生旋转</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059147.png" alt="image-20221027154120483"></p><p><strong>B+</strong> <strong>树和</strong> <strong>B</strong> <strong>树的差异：</strong></p><ul><li>B+树中非叶子节点的关键字也会同时存在在子节点中，并且是在子节点中所有关键字的最大值（或最小）。</li><li>B+树中非叶子节点仅用于索引，不保存数据记录，跟记录有关的信息都放在叶子节点中。而B树中， 非叶子节点既保存索引，也保存数据记录 。</li><li>B+树中所有关键字都在叶子节点出现，叶子节点构成一个有序链表，而且叶子节点本身按照关键字的大小从小到大顺序链接。</li></ul><h2 id="一个b-树中大概能存放多少条索引记录" tabindex="-1">一个b+树中大概能存放多少条索引记录？ <a class="header-anchor" href="#一个b-树中大概能存放多少条索引记录" aria-label="Permalink to &quot;一个b+树中大概能存放多少条索引记录？&quot;">​</a></h2><ul><li><code>真实环境</code>中一个页存放的记录数量是非常大的（默认16KB），假设指针与键值忽略不计（或看做10个字节），数据占 1 kb 的空间：</li><li>如果B+树只有1层，也就是只有1个用于存放用户记录的节点，最多能存放 16 条记录。</li><li>如果B+树有2层，最多能存放 <code>1600×16=25600</code> 条记录。</li><li>如果B+树有3层，最多能存放 <code>1600×1600×16=40960000</code> 条记录。</li><li>如果存储千万级别的数据，只需要三层就够了</li></ul><p><code>B+树的非叶子节点不存储用户记录，只存储目录记录，相对B树每个节点可以存储更多的记录，树的高度会更矮胖，IO次数也会更少。</code></p><h2 id="使用b-树存储的索引crud执行效率如何" tabindex="-1">使用B+树存储的索引crud执行效率如何？ <a class="header-anchor" href="#使用b-树存储的索引crud执行效率如何" aria-label="Permalink to &quot;使用B+树存储的索引crud执行效率如何？&quot;">​</a></h2><p>c 新增</p><p>O(lognN)</p><p>N = 高度</p><h2 id="什么是自适应哈希索引" tabindex="-1">什么是自适应哈希索引 <a class="header-anchor" href="#什么是自适应哈希索引" aria-label="Permalink to &quot;什么是自适应哈希索引&quot;">​</a></h2><p>自适应哈希索引是Innodb引擎的一个特殊功能，当它注意到某些索引值被使用的非常频繁时，会在内存中基于B-Tree所有之上再创建一个哈希索引，这就让B-Tree索引也具有哈希索引的一些优点，比如快速哈希查找。这是一个完全自动的内部行为，用户无法控制或配置，使用命令，并没有什么可配置项</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">SHOW ENGINE INNODB </span><span style="color:#F78C6C;">STATUS</span><span style="color:#A6ACCD;"> \G ;</span></span></code></pre></div><p>查看INSERT BUFFER AND ADAPTIVE HASH INDEX</p><h3 id="_12-什么是2-3树-2-3-4树" tabindex="-1">12 什么是2-3树 2-3-4树？ <a class="header-anchor" href="#_12-什么是2-3树-2-3-4树" aria-label="Permalink to &quot;12 什么是2-3树 2-3-4树？&quot;">​</a></h3><p>多叉树（multiway tree）允许<code>每个节点可以有更多的数据项和更多的子节点</code>。2-3树，2-3-4树就是多叉树，多叉树通过<code>重新组织节点，减少节点数量，增加分叉，减少树的高度</code>，能对二叉树进行优化。</p><p><strong>2-3树</strong></p><p>下面2-3树就是一颗多叉树</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059474.png" alt="image-20220709002223882"></p><p>2-3树具有如下特点：</p><ul><li>2-3树的所有叶子节点都在同一层。</li><li>有两个子节点的节点叫二节点，二节点要么没有子节点，要么有两个子节点。</li><li>有三个子节点的节点叫三节点，三节点要么没有子节点，要么有三个子节点。</li><li>2-3树是由二节点和三节点构成的树。</li><li>对于三节点的子树的值大小仍然遵守 BST 二叉排序树的规则。</li></ul><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059489.png" alt="image-20220709002554341"></p><p><strong>2-3-4树</strong></p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059509.png" alt="image-20220709004531952"></p><h2 id="为什么官方建议使用自增长主键作为索引" tabindex="-1">为什么官方建议使用自增长主键作为索引？ <a class="header-anchor" href="#为什么官方建议使用自增长主键作为索引" aria-label="Permalink to &quot;为什么官方建议使用自增长主键作为索引？&quot;">​</a></h2><p>（说一下自增主键和字符串类型主键的区别和影响）</p><ul><li>自增主键能够维持底层数据<strong>顺序写入</strong>，磁盘的顺序读写速度非常快，而磁盘的随机读写速度会慢很多</li><li>读取可以由b+树的二分查找定位</li><li>支持范围查找，范围数据自带顺序</li></ul><p>字符串无法完成以上操作</p><h2 id="记录删除问题⭐" tabindex="-1">记录删除问题⭐ <a class="header-anchor" href="#记录删除问题⭐" aria-label="Permalink to &quot;记录删除问题⭐&quot;">​</a></h2><blockquote><p>使用int自增主键后 最大id是10，删除id 10和9，再添加一条记录，最后添加的id是几？删除后重启mysql然后添加一条记录最后id是几？</p></blockquote><blockquote><ul><li><strong>如果重启，会从最大的id开始递增</strong></li><li><strong>如果没重启，会延续删除之前最大的id开始递增，</strong></li></ul></blockquote><h2 id="索引的优缺点是什么" tabindex="-1">索引的优缺点是什么 <a class="header-anchor" href="#索引的优缺点是什么" aria-label="Permalink to &quot;索引的优缺点是什么&quot;">​</a></h2><p><strong>优点</strong></p><p>聚簇（主键）索引：</p><ul><li>顺序读写</li><li>范围快速查找</li><li>范围查找自带顺序</li></ul><p>非聚簇索引：</p><ul><li>条件查询避免全表扫描scan</li><li>范围，排序，分组查询返回行id，排序分组后，再回表查询完整数据，有可能利用顺序读写</li><li>覆盖索引不需要回表操作</li></ul><p><strong>索引的代价</strong></p><p>索引是个好东西，可不能乱建，它在空间和时间上都会有消耗：</p><ul><li><strong>空间上的代价</strong></li></ul><p>每建立一个索引都要为它建立一棵B+树，<code>每一棵B+树的每一个节点都是一个数据页，一个页默认会占用 16KB 的存储空间</code>，一棵很大的B+树由许多数据页组成，那就是很大的一片存储空间。</p><ul><li><strong>时间上的代价</strong></li></ul><p><code>每次对表中的数据进行 增、删、改 操作时，都需要去修改各个B+树索引</code>。而增、删、改操作可能会对节点和记录的排序造成破坏<code>，所以存储引擎需要额外的时间进行一些记录移位、页面分裂、页面回收等操作来维护好节点和记录的排序。</code>如果我们建了许多索引，每个索引对应的B+树都要进行相关的维护操作，会给性能拖后腿。</p><p>B 树和 B+ 树都可以作为索引的数据结构，<strong>在 MySQL 中采用的是 B+ 树。</strong></p><p>但B树和B+树各有自己的应用场景，不能说B+树完全比B树好，反之亦然。</p><h2 id="使用索引一定能提升效率吗" tabindex="-1">使用索引一定能提升效率吗？ <a class="header-anchor" href="#使用索引一定能提升效率吗" aria-label="Permalink to &quot;使用索引一定能提升效率吗？&quot;">​</a></h2><p>不一定</p><ul><li>少量数据全表扫描也很快，可以直接获取到全量数据</li><li>唯一索引会影响插入速度，但建议使用</li><li>索引过多会影响更新，插入，删除数据速度</li></ul><h2 id="如果是大段文本内容-如何创建-优化-索引" tabindex="-1">如果是大段文本内容，如何创建（优化）索引？ <a class="header-anchor" href="#如果是大段文本内容-如何创建-优化-索引" aria-label="Permalink to &quot;如果是大段文本内容，如何创建（优化）索引？&quot;">​</a></h2><p>B 树和 B+ 树都可以作为 索引的数据结构，<strong>在 MySQL 中采用的是 B+ 树。</strong></p><p>第一种方式是分表存储，然后创建索引</p><p>第二是使用es为大文本创建索引</p><h2 id="什么是聚簇索引" tabindex="-1">什么是聚簇索引？ <a class="header-anchor" href="#什么是聚簇索引" aria-label="Permalink to &quot;什么是聚簇索引？&quot;">​</a></h2><p>聚簇索引数据和索引存放在一起组成一个b+树</p><p>参考005题</p><h2 id="一个表中可以有多个-非-聚簇索引吗" tabindex="-1">一个表中可以有多个（非）聚簇索引吗 <a class="header-anchor" href="#一个表中可以有多个-非-聚簇索引吗" aria-label="Permalink to &quot;一个表中可以有多个（非）聚簇索引吗&quot;">​</a></h2><blockquote><p>聚簇索引只能有一个，非聚簇索引可以有多个</p></blockquote><h2 id="聚簇索引与非聚集索引的特点是什么" tabindex="-1">聚簇索引与非聚集索引的特点是什么 <a class="header-anchor" href="#聚簇索引与非聚集索引的特点是什么" aria-label="Permalink to &quot;聚簇索引与非聚集索引的特点是什么&quot;">​</a></h2><p>参考005题</p><h2 id="crud时聚簇索引与非聚簇索引的区别是什么" tabindex="-1">CRUD时聚簇索引与非聚簇索引的区别是什么？ <a class="header-anchor" href="#crud时聚簇索引与非聚簇索引的区别是什么" aria-label="Permalink to &quot;CRUD时聚簇索引与非聚簇索引的区别是什么？&quot;">​</a></h2><ul><li>聚簇索引插入新值比采用非聚簇索引插入新值的速度要慢很多，因为插入要保证主键不能重复</li><li>聚簇索引范围，排序查找效率高，因为是有序的</li><li>非聚簇索引访问需要两次索引查找，第一次找到主键值，第二次根据主键值找到行数据</li></ul><h2 id="非聚簇索引为什么不存数据地址值而存储主键" tabindex="-1">非聚簇索引为什么不存数据地址值而存储主键？ <a class="header-anchor" href="#非聚簇索引为什么不存数据地址值而存储主键" aria-label="Permalink to &quot;非聚簇索引为什么不存数据地址值而存储主键？&quot;">​</a></h2><blockquote><p>因为聚簇索引中有时会引发分页操作、重排操作数据有可能会移动</p></blockquote><h2 id="回表操作" tabindex="-1">回表操作 <a class="header-anchor" href="#回表操作" aria-label="Permalink to &quot;回表操作&quot;">​</a></h2><h3 id="什么是回表操作" tabindex="-1">什么是回表操作 <a class="header-anchor" href="#什么是回表操作" aria-label="Permalink to &quot;什么是回表操作&quot;">​</a></h3><p>数据库表：id age name sex，id是主键，age是索引字段</p><blockquote><p>select * from user where age &gt;20 ;</p><p>首先查到所有age&gt;20的id，第一次 取回id，第二次（回表）根据id拿到完整数据</p></blockquote><h3 id="什么是覆盖索引" tabindex="-1">什么是覆盖索引 <a class="header-anchor" href="#什么是覆盖索引" aria-label="Permalink to &quot;什么是覆盖索引&quot;">​</a></h3><p>id age name sex</p><p>age -&gt; index</p><p>select * from user where age &gt;20 ;</p><p>第一次 取回id，第二次（回表）根据id拿到完整数据</p><p>age,name -&gt; index</p><p>select age from user where age &gt;20 and name like&quot;张%&quot; ;</p><p>覆盖索引不会回表查询，查询效率也是比较高的</p><h3 id="非聚集索引一定回表查询吗" tabindex="-1">非聚集索引一定回表查询吗? <a class="header-anchor" href="#非聚集索引一定回表查询吗" aria-label="Permalink to &quot;非聚集索引一定回表查询吗?&quot;">​</a></h3><blockquote><p>不一定，只要b+树中包含的字段（创建索引的字段），覆盖（包含）想要select 的字段，那么就不会回表查询了</p></blockquote><h3 id="为什么要回表-直接存数据不行吗" tabindex="-1">为什么要回表？直接存数据不行吗 <a class="header-anchor" href="#为什么要回表-直接存数据不行吗" aria-label="Permalink to &quot;为什么要回表？直接存数据不行吗&quot;">​</a></h3><blockquote><p>为了控制非聚簇索引的大小</p></blockquote><h3 id="没有主键还能回表吗" tabindex="-1">没有主键还能回表吗 <a class="header-anchor" href="#没有主键还能回表吗" aria-label="Permalink to &quot;没有主键还能回表吗&quot;">​</a></h3><blockquote><p>如果把一个 InnoDB 表的主键删掉，是不是就没有主键，就没办法进行回表查询了？</p><p>不是，InnoDB会生成rowid辅助回表查询</p></blockquote><h2 id="联合索引-组合索引-复合索引" tabindex="-1">联合索引，组合索引，复合索引 <a class="header-anchor" href="#联合索引-组合索引-复合索引" aria-label="Permalink to &quot;联合索引，组合索引，复合索引&quot;">​</a></h2><p><code>为c2和c3列建立联合索引，</code>如下所示：</p><p>c2，c3 - &gt; index</p><p>c3,c2 -&gt; index</p><p>where c3=?</p><p>全职匹配</p><p>最左前缀</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059531.png" alt="image-20220712002627554"></p><h2 id="复合索引创建时字段顺序不一样使用效果一样吗" tabindex="-1">复合索引创建时字段顺序不一样使用效果一样吗？ <a class="header-anchor" href="#复合索引创建时字段顺序不一样使用效果一样吗" aria-label="Permalink to &quot;复合索引创建时字段顺序不一样使用效果一样吗？&quot;">​</a></h2><p>我们也可以同时以多个列的大小作为排序规则，也就是同时为多个列建立索引，比方说我们想让B+树按照 <code>c2和c3列</code> 的大小进行排序，这个包含两层含义：</p><ul><li>先把各个记录和页按照<code>c2</code>列进行排序。</li><li>在记录的<code>c2</code>列相同的情况下，采用<code>c3</code>列进行排序</li><li>B+树叶子节点处的记录由<code>c2列、c3列和主键c1列组成</code></li><li>本质上也是二级索引</li></ul><p><code>create index idx_c2_c3 on user (c2,c3); </code></p><h2 id="什么是唯一索引" tabindex="-1">什么是唯一索引？ <a class="header-anchor" href="#什么是唯一索引" aria-label="Permalink to &quot;什么是唯一索引？&quot;">​</a></h2><p>随表一起创建索引：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">CREATE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">TABLE</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">customer</span><span style="color:#A6ACCD;"> (   </span></span>
<span class="line"><span style="color:#A6ACCD;">  id </span><span style="color:#C792EA;">INT</span><span style="color:#A6ACCD;"> UNSIGNED AUTO_INCREMENT,</span></span>
<span class="line"><span style="color:#A6ACCD;">  customer_no </span><span style="color:#C792EA;">VARCHAR</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">200</span><span style="color:#A6ACCD;">),</span></span>
<span class="line"><span style="color:#A6ACCD;">  customer_name </span><span style="color:#C792EA;">VARCHAR</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">200</span><span style="color:#A6ACCD;">),</span></span>
<span class="line"><span style="color:#89DDFF;">  </span><span style="color:#676E95;font-style:italic;">-- 主键索引：列设定为主键后会自动建立索引，唯一且不能为空</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#C792EA;">PRIMARY KEY</span><span style="color:#A6ACCD;">(id),</span></span>
<span class="line"><span style="color:#89DDFF;">  </span><span style="color:#676E95;font-style:italic;">-- 唯一索引：索引列值必须唯一，允许有NULL值，且NULL可能会出现多次</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F78C6C;">UNIQUE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">INDEX</span><span style="color:#A6ACCD;"> uk_no (customer_no), </span></span>
<span class="line"><span style="color:#89DDFF;">  </span><span style="color:#676E95;font-style:italic;">-- 普通索引：既不是主键，列值也不需要唯一，单纯的为了提高查询速度而创建</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F78C6C;">KEY</span><span style="color:#A6ACCD;"> idx_name (customer_name), </span></span>
<span class="line"><span style="color:#89DDFF;">  </span><span style="color:#676E95;font-style:italic;">-- 复合索引：即一个索引包含多个列</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F78C6C;">KEY</span><span style="color:#A6ACCD;"> idx_no_name (customer_no,customer_name) </span></span>
<span class="line"><span style="color:#A6ACCD;">);</span></span></code></pre></div><p>单独建创索引：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">CREATE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">TABLE</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">customer1</span><span style="color:#A6ACCD;"> (</span></span>
<span class="line"><span style="color:#A6ACCD;">  id </span><span style="color:#C792EA;">INT</span><span style="color:#A6ACCD;"> UNSIGNED,</span></span>
<span class="line"><span style="color:#A6ACCD;">  customer_no </span><span style="color:#C792EA;">VARCHAR</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">200</span><span style="color:#A6ACCD;">),</span></span>
<span class="line"><span style="color:#A6ACCD;">  customer_name </span><span style="color:#C792EA;">VARCHAR</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">200</span><span style="color:#A6ACCD;">)</span></span>
<span class="line"><span style="color:#A6ACCD;">);</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F78C6C;">ALTER</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">TABLE</span><span style="color:#A6ACCD;"> customer1 </span><span style="color:#F78C6C;">ADD</span><span style="color:#A6ACCD;"> </span><span style="color:#C792EA;">PRIMARY KEY</span><span style="color:#A6ACCD;"> customer1(id); </span><span style="color:#676E95;font-style:italic;">-- 主键索引</span></span>
<span class="line"><span style="color:#F78C6C;">CREATE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">UNIQUE INDEX</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">uk_no</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">ON</span><span style="color:#A6ACCD;"> customer1(customer_no); </span><span style="color:#676E95;font-style:italic;">-- 唯一索引</span></span>
<span class="line"><span style="color:#F78C6C;">CREATE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">INDEX</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">idx_name</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">ON</span><span style="color:#A6ACCD;"> customer1(customer_name);  </span><span style="color:#676E95;font-style:italic;">-- 普通索引</span></span>
<span class="line"><span style="color:#F78C6C;">CREATE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">INDEX</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">idx_no_name</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">ON</span><span style="color:#A6ACCD;"> customer1(customer_no,customer_name); </span><span style="color:#676E95;font-style:italic;">-- 复合索引</span></span></code></pre></div><h3 id="唯一索引是否影响性能" tabindex="-1">唯一索引是否影响性能？ <a class="header-anchor" href="#唯一索引是否影响性能" aria-label="Permalink to &quot;唯一索引是否影响性能？&quot;">​</a></h3><p>是，影响插入删除速度，但这个速度损耗可以忽略</p><h3 id="什么时候使用唯一索引" tabindex="-1">什么时候使用唯一索引？ <a class="header-anchor" href="#什么时候使用唯一索引" aria-label="Permalink to &quot;什么时候使用唯一索引？&quot;">​</a></h3><p>业务需求唯一字段的时候，一般不考虑性能问题，如下是阿里开发规约</p><blockquote><p>【强制】业务上具有唯一特性的字段，即使是多个字段的组合，也必须建成唯一索引。 说明：不要以为唯一索引影响了 insert 速度，这个速度损耗可以忽略，但提高查找速度是明 显的；另外，即使在应用层做了非常完善的校验控制，只要没有唯一索引，根据墨菲定律，必 然有脏数据产生。</p></blockquote><h2 id="什么时候适合创建索引" tabindex="-1">什么时候适合创建索引 <a class="header-anchor" href="#什么时候适合创建索引" aria-label="Permalink to &quot;什么时候适合创建索引&quot;">​</a></h2><h3 id="适合创建索引" tabindex="-1">适合创建索引 <a class="header-anchor" href="#适合创建索引" aria-label="Permalink to &quot;适合创建索引&quot;">​</a></h3><blockquote><ul><li><p>频繁作为where条件语句查询字段</p></li><li><p>关联字段需要建立索引</p></li><li><p>排序字段可以建立索引</p></li><li><p>分组字段可以建立索引(因为分组前提是排序)</p></li><li><p>统计字段可以建立索引（如.count(),max()）</p></li></ul></blockquote><h3 id="不适合创建索引" tabindex="-1">不适合创建索引 <a class="header-anchor" href="#不适合创建索引" aria-label="Permalink to &quot;不适合创建索引&quot;">​</a></h3><ul><li><p>频繁更新的字段不适合建立索引</p></li><li><p>where，分组，排序中用不到的字段不必要建立索引</p></li><li><p>可以确定表数据非常少不需要建立索引</p></li><li><p>参与mysql函数计算的列不适合建索引</p></li></ul><p>创建索引时避免有如下极端误解：</p><p>1）宁滥勿缺。认为一个查询就需要建一个索引。</p><p>2）宁缺勿滥。认为索引会消耗空间、严重拖慢更新和新增速度。</p><p>3）抵制惟一索引。认为业务的惟一性一律需要在应用层通过“先查后插”方式解决。</p><h2 id="什么是索引下推" tabindex="-1">什么是索引下推？ <a class="header-anchor" href="#什么是索引下推" aria-label="Permalink to &quot;什么是索引下推？&quot;">​</a></h2><p>5.6之前的版本是没有索引下推这个优化的</p><p>**Using index condition：**叫作 <code>Index Condition Pushdown Optimization （索引下推优化）</code></p><ul><li><code>如果没有索引下推（ICP）</code>，那么MySQL在存储引擎层找到满足<code>content1 &gt; &#39;z&#39;</code>条件的第一条二级索引记录。<code>主键值进行回表</code>，返回完整的记录给server层，server层再判断其他的搜索条件是否成立。如果成立则保留该记录，否则跳过该记录，然后向存储引擎层要下一条记录。</li><li><code>如果使用了索引下推（ICP</code>），那么MySQL在存储引擎层找到满足<code>content1 &gt; &#39;z&#39;</code>条件的第一条二级索引记录。<code>不着急执行回表</code>，而是在这条记录上先判断一下所有关于<code>idx_content1</code>索引中包含的条件是否成立，也就是<code>content1 &gt; &#39;z&#39; AND content1 LIKE &#39;%a&#39;</code>是否成立。如果这些条件不成立，则直接跳过该二级索引记录，去找下一条二级索引记录；如果这些条件成立，则执行回表操作，返回完整的记录给server层。</li></ul><blockquote><p>未开启索引下推：根据筛选条件在索引树中筛选第一个条件，获得结果集后回表操作，进行其他条件筛选，再次回表查询</p></blockquote><blockquote><p>开启索引下推：在条件查询时，<strong>当前索引树如果满足全部筛选条件，可以在当前树中完成全部筛选过滤，得到比较小的结果集再进行回表操作</strong>。优点是减少回表操作，提高查询性能</p></blockquote><h2 id="哪些情况会导致索引失效" tabindex="-1">哪些情况会导致索引失效？ <a class="header-anchor" href="#哪些情况会导致索引失效" aria-label="Permalink to &quot;哪些情况会导致索引失效？&quot;">​</a></h2><p>计算、函数导致索引失效</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">-- 显示查询分析</span></span>
<span class="line"><span style="color:#A6ACCD;">EXPLAIN SELECT * FROM emp WHERE emp.name  LIKE &#39;abc%&#39;;</span></span>
<span class="line"><span style="color:#A6ACCD;">EXPLAIN SELECT * FROM emp WHERE LEFT(emp.name,3) = &#39;abc&#39;; --索引失效</span></span></code></pre></div><p>LIKE以%，_ 开头索引失效</p><blockquote><p><strong>拓展：Alibaba《Java开发手册》</strong></p><p>【强制】页面搜索严禁左模糊或者全模糊，如果需要请走搜索引擎来解决。</p></blockquote><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN SELECT * FROM emp WHERE name LIKE &#39;%ab%&#39;; --索引失效</span></span></code></pre></div><p>不等于(!= 或者&lt;&gt;)索引失效</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.name = &#39;abc&#39; ;</span></span>
<span class="line"><span style="color:#A6ACCD;">EXPLAIN SELECT SQL_NO_CACHE * FROM emp WHERE emp.name &lt;&gt; &#39;abc&#39; ; --索引失效</span></span></code></pre></div><p>IS NOT NULL 失效 和 IS NULL</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN SELECT * FROM emp WHERE emp.name IS NULL;</span></span>
<span class="line"><span style="color:#A6ACCD;">EXPLAIN SELECT * FROM emp WHERE emp.name IS NOT NULL; --索引失效</span></span></code></pre></div><p>**注意：**当数据库中的数据的索引列的<code>NULL值达到比较高的比例的时候</code>，即使在IS NOT NULL 的情况下 MySQL的查询优化器会选择使用索引，<code>此时type的值是range（范围查询）</code></p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 将 id&gt;20000 的数据的 name 值改为 NULL</span></span>
<span class="line"><span style="color:#F78C6C;">UPDATE</span><span style="color:#A6ACCD;"> emp </span><span style="color:#F78C6C;">SET</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">NULL</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">20000</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 执行查询分析，可以发现 IS NOT NULL 使用了索引</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 具体多少条记录的值为NULL可以使索引在IS NOT NULL的情况下生效，由查询优化器的算法决定</span></span>
<span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> emp </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> emp.name </span><span style="color:#F78C6C;">IS NOT NULL</span></span></code></pre></div><p>类型转换导致索引失效</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> emp </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">name</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">123</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">; </span></span>
<span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> emp </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">name</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">123</span><span style="color:#A6ACCD;">; </span><span style="color:#676E95;font-style:italic;">--索引失效</span></span></code></pre></div><p>复合索引未用左列字段失效</p><p>如果mysql觉得全表扫描更快时（数据少）;</p><h2 id="为什么like以-开头索引会失效" tabindex="-1">为什么LIKE以%开头索引会失效？ <a class="header-anchor" href="#为什么like以-开头索引会失效" aria-label="Permalink to &quot;为什么LIKE以%开头索引会失效？&quot;">​</a></h2><p>id,name,age</p><p>name 创建索引</p><p>select * from user where name like &#39;%明&#39;</p><p>type=all</p><p>select name,id from user where name like &#39;%明&#39;</p><p>type=index</p><p>张明</p><p>(name,age)</p><p>其实并不会完全失效，覆盖索引下会出现type=index，表示遍历了索引树，再回表查询，覆盖索引没有生效的时会直接type=all，没有高效使用索引是因为字符串索引会逐个转换成accii码，生成b+树时按首个字符串顺序排序，类似复合索引未用左列字段失效一样，跳过开始部分也就无法使用生成的b+树了</p><h3 id="一个表有多个索引的时候-能否手动选择使用哪个索引" tabindex="-1">一个表有多个索引的时候，能否手动选择使用哪个索引？ <a class="header-anchor" href="#一个表有多个索引的时候-能否手动选择使用哪个索引" aria-label="Permalink to &quot;一个表有多个索引的时候，能否手动选择使用哪个索引？&quot;">​</a></h3><blockquote><p>不可用手动直接干预，只能通过mysql优化器自动选择</p></blockquote><h2 id="如何查看一个表的索引" tabindex="-1">如何查看一个表的索引 <a class="header-anchor" href="#如何查看一个表的索引" aria-label="Permalink to &quot;如何查看一个表的索引&quot;">​</a></h2><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">show </span><span style="color:#F78C6C;">index</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_emp; </span><span style="color:#89DDFF;">//</span><span style="color:#A6ACCD;"> 显示表上的索引</span></span>
<span class="line"><span style="color:#A6ACCD;">explain </span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t_emp </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> id</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">; </span><span style="color:#89DDFF;">//</span><span style="color:#A6ACCD;"> 显示可能会用到的索引及最终使用的索引</span></span></code></pre></div><h2 id="能否查看到索引选择的逻辑-是否使用过optimizer-trace" tabindex="-1">能否查看到索引选择的逻辑？是否使用过optimizer_trace？ <a class="header-anchor" href="#能否查看到索引选择的逻辑-是否使用过optimizer-trace" aria-label="Permalink to &quot;能否查看到索引选择的逻辑？是否使用过optimizer_trace？&quot;">​</a></h2><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">set</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">session</span><span style="color:#A6ACCD;"> optimizer_trace</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">enabled=on</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">,end_markers_in_json</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">on</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> information_schema.OPTIMIZER_TRACE;</span></span>
<span class="line"><span style="color:#F78C6C;">set</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">session</span><span style="color:#A6ACCD;"> optimizer_trace</span><span style="color:#89DDFF;">=</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">enabled=off</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><h2 id="多个索引优先级是如何匹配的" tabindex="-1">多个索引优先级是如何匹配的？ <a class="header-anchor" href="#多个索引优先级是如何匹配的" aria-label="Permalink to &quot;多个索引优先级是如何匹配的？&quot;">​</a></h2><ol><li>主键（唯一索引）匹配</li><li>全值匹配（单值匹配）</li><li>最左前缀匹配</li><li>范围匹配</li><li>索引扫描</li><li>全表扫描</li></ol><p>一般性建议</p><ul><li>对于单键索引，尽量选择过滤性更好的索引（例如：手机号，邮件，身份证）</li><li>在选择组合索引的时候，过滤性最好的字段在索引字段顺序中，位置越靠前越好。</li><li>选择组合索引时，尽量包含where中更多字段的索引</li><li>组合索引出现范围查询时，尽量把这个字段放在索引次序的最后面</li><li>尽量避免造成索引失效的情况</li></ul><h2 id="使用order-by时能否通过索引排序" tabindex="-1">使用Order By时能否通过索引排序？ <a class="header-anchor" href="#使用order-by时能否通过索引排序" aria-label="Permalink to &quot;使用Order By时能否通过索引排序？&quot;">​</a></h2><blockquote><p>没有过滤条件(where)不走索引</p></blockquote><h2 id="通过索引排序内部流程是什么" tabindex="-1">通过索引排序内部流程是什么？ <a class="header-anchor" href="#通过索引排序内部流程是什么" aria-label="Permalink to &quot;通过索引排序内部流程是什么？&quot;">​</a></h2><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;">,id  </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;">  </span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">like</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%明</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;">；</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;">,id，age  </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> user </span><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;">  </span><span style="color:#F78C6C;">name</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">like</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%明</span><span style="color:#89DDFF;">&#39;</span></span></code></pre></div><p>关键配置：</p><ul><li>sort_buffer可供排序的内存缓冲区大小</li><li>max_length_for_sort_data 单行所有字段总和限制，超过这个大小启动双路排序</li></ul><ol><li>通过索引检过滤筛选条件索到需要排序的字段+其他字段（如果是符合索引）</li><li>判断索引内容是否覆盖select的字段 <ol><li>如果覆盖索引，select的字段和排序都在索引上，那么在内存中进行排序，排序后输出结果</li><li>如果索引没有覆盖查询字段，接下来计算select的字段是否超过max_length_for_sort_data限制，如果超过，启动双路排序，否则使用单路</li></ol></li></ol><h2 id="什么是双路排序和单路排序" tabindex="-1">什么是双路排序和单路排序 <a class="header-anchor" href="#什么是双路排序和单路排序" aria-label="Permalink to &quot;什么是双路排序和单路排序&quot;">​</a></h2><p>单路排序：一次取出所有字段进行排序，内存不够用的时候会使用磁盘</p><p>双路排序：取出排序字段进行排序，排序完成后再次回表查询所需要的其他字段</p><p>如果不在索引列上，filesort有两种算法： mysql就要启动双路排序和单路排序</p><p><strong>双路排序（慢）</strong></p><p>Select id,age,name from stu order by name;</p><p>Ø MySQL 4.1之前是使用双路排序，字面意思就是两次扫描磁盘，最终得到数据， 读取行指针和order by列，对他们进行排序，然后扫描已经排序好的列表，按照列表中的值重新从列表中读取对应的数据输出</p><p>Ø 从磁盘取排序字段，在buffer进行排序，再从磁盘取其他字段。</p><p>Ø 取一批数据，要对磁盘进行两次扫描，众所周知，I\O是很耗时的，所以在mysql4.1之后，出现了第二种改进的算法，就是单路排序。</p><p><strong>单路排序（快）</strong></p><p>从磁盘读取查询需要的所有列，按照order by列在buffer对它们进行排序，然后扫描排序后的列表进行输出， 它的效率更快一些，避免了第二次读取数据。并且把随机IO变成了顺序IO，但是它会使用更多的空间， 因为它把每一行都保存在内存中了。</p><p><strong>结论及引申出的问题</strong></p><p>但是用单路有问题</p><p>在sort_buffer中，单路比多路要多占用很多空间，因为单路是把所有字段都取出, 所以有可能取出的数据的总大小超出了sort_buffer的容量，导致每次只能取sort_buffer容量大小的数据，进行排序（创建tmp文件，多路合并），排完再取sort_buffer容量大小，再排……从而多次I/O。</p><p>单路本来想省一次I/O操作，反而导致了大量的I/O操作，反而得不偿失。</p><p><strong>优化策略</strong></p><p>Ø 增大sort_buffer_size参数的设置</p><p>Ø 增大max_length_for_sort_data参数的设置</p><p>Ø 减少select 后面的查询的字段。 禁止使用select *</p><p><strong>提高Order By的速度</strong></p><p>\1. Order by时select * 是一个大忌。只Query需要的字段， 这点非常重要。在这里的影响是：</p><p>l 当Query的字段大小总和小于max_length_for_sort_data 而且排序字段不是 TEXT|BLOB 类型时，会用改进后的算法——单路排序， 否则用老算法——多路排序。</p><p>l 两种算法的数据都有可能超出sort_buffer的容量，超出之后，会创建tmp文件进行合并排序，导致多次I/O，但是用单路排序算法的风险会更大一些，所以要提高sort_buffer_size。</p><p>\2. 尝试提高 sort_buffer_size</p><p>l 不管用哪种算法，提高这个参数都会提高效率，当然，要根据系统的能力去提高，因为这个参数是针对每个进程（connection）的 1M-8M之间调整。 MySQL5.7和8.0，InnoDB存储引擎默认值是1048576字节，1MB。</p><p>SHOW VARIABLES LIKE &#39;%sort_buffer_size%&#39;;</p><p>​</p><p>\3. 尝试提高 max_length_for_sort_data</p><p>l 提高这个参数， 会增加用改进算法的概率。</p><p>SHOW VARIABLES LIKE &#39;%max_length_for_sort_data%&#39;;</p><p>#5.7默认1024字节</p><p>#8.0默认4096字节</p><p>l 但是如果设的太高，数据总容量超出sort_buffer_size的概率就增大，明显症状是高的磁盘I/O活动和低的处理器使用率。如果需要返回的列的总长度大于max_length_for_sort_data，使用双路算法，否则使用单路算法。1024-8192字节之间调整</p><h2 id="group-by-分组和order-by在索引使用上有什么区别" tabindex="-1">group by 分组和order by在索引使用上有什么区别？ <a class="header-anchor" href="#group-by-分组和order-by在索引使用上有什么区别" aria-label="Permalink to &quot;group by 分组和order by在索引使用上有什么区别？&quot;">​</a></h2><p>group by 使用索引的原则几乎跟order by一致 ，唯一区别：</p><ul><li>group by 先排序再分组，遵照索引建的最佳左前缀法则</li><li>group by没有过滤条件，也可以用上索引。Order By 必须有过滤条件才能使用上索引。</li></ul><h2 id="如果表中有字段为null-又被经常查询该不该给这个字段创建索引" tabindex="-1">如果表中有字段为null，又被经常查询该不该给这个字段创建索引？ <a class="header-anchor" href="#如果表中有字段为null-又被经常查询该不该给这个字段创建索引" aria-label="Permalink to &quot;如果表中有字段为null，又被经常查询该不该给这个字段创建索引？&quot;">​</a></h2><p>应该创建索引，使用的时候尽量使用is null判断。</p><p>IS NOT NULL 失效 和 IS NULL</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> emp </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> emp.name </span><span style="color:#F78C6C;">IS</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">NULL</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> emp </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> emp.name </span><span style="color:#F78C6C;">IS NOT NULL</span><span style="color:#A6ACCD;">; </span><span style="color:#676E95;font-style:italic;">--索引失效</span></span></code></pre></div><p>**注意：**当数据库中的数据的索引列的<code>NULL值达到比较高的比例的时候</code>，即使在IS NOT NULL 的情况下 MySQL的查询优化器会选择使用索引，<code>此时type的值是range（范围查询）</code></p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 将 id&gt;20000 的数据的 name 值改为 NULL</span></span>
<span class="line"><span style="color:#F78C6C;">UPDATE</span><span style="color:#A6ACCD;"> emp </span><span style="color:#F78C6C;">SET</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">NULL</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">id</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">20000</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 执行查询分析，可以发现 IS NOT NULL 使用了索引</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 具体多少条记录的值为NULL可以使索引在IS NOT NULL的情况下生效，由查询优化器的算法决定</span></span>
<span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> emp </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> emp.name </span><span style="color:#F78C6C;">IS NOT NULL</span></span></code></pre></div><h2 id="有字段为null索引是否会失效" tabindex="-1">有字段为null索引是否会失效 <a class="header-anchor" href="#有字段为null索引是否会失效" aria-label="Permalink to &quot;有字段为null索引是否会失效&quot;">​</a></h2><blockquote><p>不一定会失效，每一条SQL具体有没有使用索引可以通过trace追踪一下，最好还是给上默认值</p><p>数字类型的给0，字符串给个空串“”，</p></blockquote><h1 id="mysql-内部技术架构-⭐" tabindex="-1">MySQL 内部技术架构 ⭐ <a class="header-anchor" href="#mysql-内部技术架构-⭐" aria-label="Permalink to &quot;MySQL 内部技术架构 ⭐&quot;">​</a></h1><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.1.30/202212311412879.png" alt="image-20221231141202793" style="zoom:67%;"><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059803.png" alt="image-20221028155608009"></p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059821.png" alt="img"></p><h2 id="mysql内部支持缓存查询吗" tabindex="-1">MySQL内部支持缓存查询吗 <a class="header-anchor" href="#mysql内部支持缓存查询吗" aria-label="Permalink to &quot;MySQL内部支持缓存查询吗&quot;">​</a></h2><blockquote><p>当MySQL接收到客户端的查询SQL之后，仅仅只需要对其进行相应的权限验证之后，就会通过Query Cache来查找结果，甚至都不需要经过Optimizer模块进行执行计划的分析优化，更不需要发生任何存储引擎的交互</p></blockquote><p>mysql5.7支持内部缓存，8.0之后就废弃掉了</p><h3 id="mysql8为何废弃掉查询缓存" tabindex="-1">MySQL8为何废弃掉查询缓存？ <a class="header-anchor" href="#mysql8为何废弃掉查询缓存" aria-label="Permalink to &quot;MySQL8为何废弃掉查询缓存？&quot;">​</a></h3><p>缓存的意义在于快速查询提升系统性能，可以灵活控制缓存的一致性，mysql缓存的限制</p><blockquote><ol><li>mysql基本没有手段灵活的管理缓存失效和生效，尤其对于频繁更新的表</li><li>SQL必须完全一致才会导致cache命中</li><li>为了节省内存空间，太大的result set不会被cache (&lt; query_cache_limit)；</li><li>MySQL缓存在分库分表环境下是不起作用的；</li><li>执行SQL里有触发器,自定义函数时，MySQL缓存也是不起作用的；</li><li>在表的结构或数据发生改变时，基于该表相关cache立即全部失效。</li></ol></blockquote><h3 id="替代方案是什么" tabindex="-1">替代方案是什么？ <a class="header-anchor" href="#替代方案是什么" aria-label="Permalink to &quot;替代方案是什么？&quot;">​</a></h3><blockquote><p>应用层组织缓存，最简单的是使用redis，ehcached等</p></blockquote><h3 id="mysql内部核心模块组成" tabindex="-1">MySQL内部核心模块组成 <a class="header-anchor" href="#mysql内部核心模块组成" aria-label="Permalink to &quot;MySQL内部核心模块组成&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059002.png" alt="image-20220627113443003" style="zoom:67%;"><p><strong>Connectors（客户端）</strong></p><p>MySQL服务器之外的客户端程序，与具体的语言相关，例如Java中的JDBC，图形用户界面SQLyog等。<code>本质上都是在TCP连接上通过MySQL协议和MySQL服务器进行通信。</code></p><p><strong>MySQL Server（服务器）</strong></p><p><strong>第1层：连接层</strong></p><ul><li>系统（客户端）访问 MySQL 服务器前，做的<code>第一件事就是建立 TCP 连接</code>。</li><li>经过三次握手建立连接成功后， MySQL 服务器对 TCP 传输过来的账号密码做<code>身份认证、权限获取</code>。 <ul><li>用户名或密码不对<code>，会收到一个</code>Access denied for user<code>错误，客户端程序结束执行</code></li><li><code>用户名密码认证通过</code>，会从权限表<code>查出账号拥有的权限</code>与连接关联，之后的权限判断逻辑，都将依赖于此时读到的权限</li></ul></li><li>TCP 连接收到请求后，必须要分配给一个线程专门与这个客户端的交互。所以还会有个线程池，去走后面的流程。每一个连接从线程池中获取线程，省去了创建和销毁线程的开销。</li></ul><p><strong>第2层：服务层</strong></p><p><strong>Management Serveices &amp; Utilities： 系统管理和控制工具</strong></p><p><strong>SQL Interface：SQL接口：</strong></p><ul><li><code>接收用户的SQL命令，并且返回用户需要查询的结果。</code>比如SELECT ... FROM就是调用SQL Interface</li><li>MySQL支持DML（数据操作语言）、DDL（数据定义语言）、存储过程、视图、触发器、自定义函数等多种SQL语言接口</li></ul><p><strong>Parser：解析器：</strong></p><p>在SQL命令传递到解析器的时候会被解析器验证和解析。解析器中SQL 语句进行<code>语法分析、语法解析</code>，并为其创建<code>语法树</code>。</p><p><strong>语法分析</strong></p><p>语法分析主要是把输入转化成若干个tokens，包含key和非key。</p><p>在分析之后，会得到4个Token，其中有2个key，它们分别是SELECT、FROM。</p><table><thead><tr><th>key</th><th>非key</th><th>key</th><th>非key</th></tr></thead><tbody><tr><td>SELECT</td><td>age</td><td>FROM</td><td>user</td></tr></tbody></table><p>典型的解析树如下：</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059019.png" alt="image-20220702002430362"></p><p><strong>Optimizer：查询优化器：</strong></p><ul><li>SQL语句在语法解析后、查询前会使用查询优化器对查询进行优化，<code>确定SQL语句的执行路径，生成一个执行计划</code>。</li></ul><p><strong>Caches &amp; Buffers： 查询缓存组件：</strong></p><ul><li>MySQL内部维持着一些Cache和Buffer，比如Query Cache用来缓存一条SELECT语句的执行结果，如果能够在其中找到对应的查询结果，那么就不必再进行查询解析、查询优化和执行的整个过程了，直接将结果反馈给客户端。</li><li>这个缓存机制是由一系列小缓存组成的。比如表缓存，记录缓存，key缓存，权限缓存等 。</li><li>这个查询缓存可以在不同客户端之间共享 。</li></ul><p><strong>第3层：引擎层</strong></p><p>插件式存储引擎层（ Storage Engines），<code>负责MySQL中数据的存储和提取，对物理服务器级别维护的底层数据执行操作，服务器通过API与存储引擎进行通信</code>。不同的存储引擎具有的功能不同，管理的表有不同的存储结构，采用的存取算法也不同，这样我们可以根据自己的实际需要进行选取。例如MyISAM引擎和InnoDB引擎。</p><p><strong>存储层</strong></p><p>所有的数据、数据库、表的定义、表的每一行的内容、索引，都是存在<code>文件系统</code> 上，以文件的方式存在，并完成与存储引擎的交互。</p><h2 id="mysql-执行查询语句的内部执行过程" tabindex="-1">MySQL 执行查询语句的内部执行过程 <a class="header-anchor" href="#mysql-执行查询语句的内部执行过程" aria-label="Permalink to &quot;MySQL 执行查询语句的内部执行过程&quot;">​</a></h2><p>一条sql发送给mysql后，内部是如何执行的？（说一下 MySQL 执行一条查询语句的内部执行过程？）</p><p>查询流程说明</p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059034.png" alt="image-20220627141453944"></p><p><strong>首先，</strong><code>MySQL客户端通过协议与MySQL服务器建连接，通过SQL接口发送SQL语句，先检查查询缓存，如果命中，直接返回结果，否则进行语句解析。</code>也就是说，在解析查询之前，服务器会先访问查询缓存，如果某个查询结果已经位于缓存中，服务器就不会再对查询进行解析、优化、以及执行。它仅仅将缓存中的结果返回给用户即可，这将大大提高系统的性能。</p><p><strong>接下来，</strong><code>MySQL解析器通过关键字将SQL语句进行解析，并生成一棵对应的解析树，</code>解析器使用MySQL语法规则验证和解析SQL语句。例如，它将验证是否使用了错误的关键字，或者使用关键字的顺序是否正确，引号能否前后匹配等；<code>预处理器则根据MySQL规则进一步检查解析树是否合法，</code>例如，这里将检查数据表和数据列是否存在，还会解析名字和别名，看是否有歧义等。<code>然后预处理器会进行查询重写，生成一棵新解析树。</code></p><p><strong>接下来，</strong><code>查询优化器将解析树转化成执行计划。</code>MySQL优化程序会对我们的语句做一些优化，如子查询转换为连接、表达式简化等等。优化的结果就是生成一个执行计划，这个执行计划表明了应该使用哪些索引执行查询，以及表之间的连接顺序是啥样，等等。我们可以使用EXPLAIN语句来查看某个语句的执行计划。</p><p><strong>最后，</strong><code>进入执行器阶段。</code>完成查询优化后，<code>查询执行引擎</code>会按照生成的执行计划调用存储引擎提供的接口执行SQL查询并将结果返回给客户端。在MySQL8以下的版本，如果设置了查询缓存，这时会将查询结果进行缓存，再返回给客户端。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059402.png" alt="img"><h3 id="mysql-提示-不存在此列-是执行到哪个节点报出的" tabindex="-1">MySQL 提示“不存在此列”是执行到哪个节点报出的？ <a class="header-anchor" href="#mysql-提示-不存在此列-是执行到哪个节点报出的" aria-label="Permalink to &quot;MySQL 提示“不存在此列”是执行到哪个节点报出的？&quot;">​</a></h3><blockquote><p>是在Parser：解析器 分析sql语法的时候检查的列。</p></blockquote><h3 id="如果一张表创建了多个索引-在哪个阶段或模块进行的索引选择" tabindex="-1">如果一张表创建了多个索引，在哪个阶段或模块进行的索引选择？ <a class="header-anchor" href="#如果一张表创建了多个索引-在哪个阶段或模块进行的索引选择" aria-label="Permalink to &quot;如果一张表创建了多个索引，在哪个阶段或模块进行的索引选择？&quot;">​</a></h3><blockquote><p>在优化器阶段<strong>Optimizer：查询优化器：</strong></p></blockquote><h2 id="mysql-默认存储引擎" tabindex="-1">MySQL 默认存储引擎 <a class="header-anchor" href="#mysql-默认存储引擎" aria-label="Permalink to &quot;MySQL 默认存储引擎&quot;">​</a></h2><p>查看MySQL提供什么存储引擎</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">show engines ;</span></span></code></pre></div><p>下面表示MySQL中默认使用的存储引擎是InnoDB，支持事务，行锁，外键，支持分布式事务(XA)，支持保存点(回滚)</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.1.30/202212311350886.png" alt="image-20221231135039770" style="zoom:80%;"><p>也可以通过以下语句查看默认的存储引擎：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">show variables </span><span style="color:#F78C6C;">like</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%default_storage_engine%</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.1.30/202212311353971.png" alt="image-20221231135303894" style="zoom:80%;"><h2 id="mysql8自带哪些存储引擎-⭐" tabindex="-1">MySQL8自带哪些存储引擎 ⭐ <a class="header-anchor" href="#mysql8自带哪些存储引擎-⭐" aria-label="Permalink to &quot;MySQL8自带哪些存储引擎 ⭐&quot;">​</a></h2><h3 id="innodb引擎" tabindex="-1">InnoDB引擎 <a class="header-anchor" href="#innodb引擎" aria-label="Permalink to &quot;InnoDB引擎&quot;">​</a></h3><ul><li><p>InnoDB是MySQL的默认事务型引擎，它被设计用来<code>处理大量的短期(short-lived)事务</code>。可以确保事务的完整提交(Commit)和回滚(Rollback)。</p></li><li><p>除非有非常特别的原因需要使用其他的存储引擎，否则<code>应该优先考虑InnoDB引擎</code>。</p></li><li><p>数据文件结构：表名.frm 存储表结构（MySQL8.0时，合并在表名.ibd中）</p><ul><li>表名.ibd 存储数据和索引</li></ul></li><li><p>InnoDB不仅缓存索引还要缓存真实数据， 对内存要求较 高 ，而且内存大小对性能有决定性的影响。</p></li></ul><h3 id="myisam引擎" tabindex="-1">MyISAM引擎 <a class="header-anchor" href="#myisam引擎" aria-label="Permalink to &quot;MyISAM引擎&quot;">​</a></h3><ul><li><p>MyISAM提供了大量的特性，包括全文索引、压缩、空间函数(GIS)等，但<code>MyISAM不支持事务和行级锁</code>，有一个毫无疑问的缺陷就是崩溃后无法安全恢复。</p></li><li><p>优势是访问的 速度快 ，对事务完整性没有要求或者以SELECT、INSERT为主的应用。</p></li><li><p>数据文件结构：表名.frm 存储表结构</p><ul><li><p>表名.MYD 存储数据</p></li><li><p>表名.MYI 存储索引</p></li></ul></li><li><p>MyISAM只缓存索引，不缓存真实数据。</p></li></ul><h3 id="archive引擎" tabindex="-1">Archive引擎 <a class="header-anchor" href="#archive引擎" aria-label="Permalink to &quot;Archive引擎&quot;">​</a></h3><ul><li><code>Archive档案存储引擎只支持INSERT和SELECT操作</code>。</li><li>Archive表适合日志和数据采集（档案）类应用。</li><li>根据英文的测试结论来看，Archive表比MyISAM表要小大约75%，比支持事务处理的InnoDB表小大约83%。</li></ul><h3 id="blackhole引擎" tabindex="-1">Blackhole引擎 <a class="header-anchor" href="#blackhole引擎" aria-label="Permalink to &quot;Blackhole引擎&quot;">​</a></h3><ul><li><code>Blackhole引擎没有实现任何存储机制，它会丢弃所有插入的数据，不做任何保存</code>。</li><li>但服务器会记录Blackhole表的日志，所以可以用于复制数据到备库，或者简单地记录到日志。但这种应用方式会碰到很多问题，因此并不推荐。</li></ul><h3 id="csv引擎" tabindex="-1">CSV引擎 <a class="header-anchor" href="#csv引擎" aria-label="Permalink to &quot;CSV引擎&quot;">​</a></h3><ul><li><code>CSV引擎可以将普通的CSV文件作为MySQL的表来处理，但不支持索引</code>。</li><li>CSV引擎可以作为一种数据交换的机制，非常有用。</li><li>CSV存储的数据直接可以在操作系统里，用文本编辑器，或者excel读取。</li></ul><h3 id="memory引擎" tabindex="-1">Memory引擎 <a class="header-anchor" href="#memory引擎" aria-label="Permalink to &quot;Memory引擎&quot;">​</a></h3><ul><li>如果需要快速地访问数据，并且这些数据不会被修改，重启以后丢失也没有关系，那么使用Memory表是非常有用。</li><li>Memory表至少比MyISAM表要快一个数量级。</li></ul><h3 id="federated引擎" tabindex="-1">Federated引擎 <a class="header-anchor" href="#federated引擎" aria-label="Permalink to &quot;Federated引擎&quot;">​</a></h3><p><code>Federated引擎是访问其他MySQL服务器的一个代理（跨库关联查询）</code>，尽管该引擎看起来提供了一种很好的跨服务器的灵活性，但也经常带来问题，因此默认是禁用的。</p><h2 id="mysql-存储引擎架构了解吗" tabindex="-1">MySQL 存储引擎架构了解吗？ <a class="header-anchor" href="#mysql-存储引擎架构了解吗" aria-label="Permalink to &quot;MySQL 存储引擎架构了解吗？&quot;">​</a></h2><p><a href="https://dev.mysql.com/doc/refman/5.7/en/innodb-architecture.html" target="_blank" rel="noreferrer">https://dev.mysql.com/doc/refman/5.7/en/innodb-architecture.html</a></p><p>下面是官方的InnoDB引擎结构图，主要分为内存结构和磁盘结构两大部分。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059820.png" alt="img" style="zoom:67%;"><h3 id="内存区域" tabindex="-1">内存区域 <a class="header-anchor" href="#内存区域" aria-label="Permalink to &quot;内存区域&quot;">​</a></h3><blockquote><p><strong>Buffer Pool</strong>:在InnoDB访问表记录和索引时会在Buffer Pool的页中缓存，以后使用可以减少磁盘IO操作，提升效率。主要用来缓存热的数据页和索引页。</p></blockquote><blockquote><p><strong>Log Buffer</strong>：用来缓存redolog</p><p><strong>Adaptive Hash Index</strong>：自适应哈希索引</p></blockquote><blockquote><p><strong>Change Buffer</strong>:它是一种应用在非唯一普通索引页（non-unique secondary index page）不在缓冲池中，对页进行了写操作，并不会立刻将磁盘页加载到缓冲池，而仅仅记录缓冲变更（Buffer Changes），等未来数据被读取时，再将数据合并（Merge）恢复到缓冲池中的技术。写缓冲的目的是降低写操作的磁盘IO，提升数据库性能。</p></blockquote><h3 id="磁盘区域" tabindex="-1">磁盘区域 <a class="header-anchor" href="#磁盘区域" aria-label="Permalink to &quot;磁盘区域&quot;">​</a></h3><p>磁盘中的结构分为两大类：表空间和重做日志。</p><blockquote><ul><li>表空间：分为系统表空间(MySQL 目录的 ibdata1 文件)，临时表空间，常规表空间，Undo 表空间以及 file-per-table 表空间(MySQL5.7默认打开file_per_table 配置）。系统表空间又包括了InnoDB数据字典，双写缓冲区(Doublewrite Buffer)，修改缓存(Change Buffer），Undo日志等。</li><li>Redo日志：存储的就是 Log Buffer 刷到磁盘的数据。</li></ul></blockquote><p>官方文档：<a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-storage-engine.html" target="_blank" rel="noreferrer">https://dev.mysql.com/doc/refman/8.0/en/innodb-storage-engine.html</a></p><h2 id="能否单独为一张表设置存储引擎" tabindex="-1">能否单独为一张表设置存储引擎 <a class="header-anchor" href="#能否单独为一张表设置存储引擎" aria-label="Permalink to &quot;能否单独为一张表设置存储引擎&quot;">​</a></h2><h3 id="设置默认存储引擎" tabindex="-1">设置默认存储引擎 <a class="header-anchor" href="#设置默认存储引擎" aria-label="Permalink to &quot;设置默认存储引擎&quot;">​</a></h3><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">SET</span><span style="color:#A6ACCD;"> DEFAULT_STORAGE_ENGINE</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">MyISAM;</span></span></code></pre></div><h3 id="修改配置文件" tabindex="-1">修改配置文件 <a class="header-anchor" href="#修改配置文件" aria-label="Permalink to &quot;修改配置文件&quot;">​</a></h3><blockquote><p>或者修改 my.cnf 文件：vim /etc/my.cnf 新增一行：default-storage-engine=MyISAM 重启MySQL：systemctl restart mysqld</p></blockquote><h3 id="直接表设置" tabindex="-1">直接表设置 <a class="header-anchor" href="#直接表设置" aria-label="Permalink to &quot;直接表设置&quot;">​</a></h3><p>我们可以为 不同的表设置不同的存储引擎</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">CREATE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">TABLE</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">表名</span><span style="color:#A6ACCD;">( 建表语句; ) ENGINE </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> 存储引擎名称;</span></span>
<span class="line"><span style="color:#F78C6C;">ALTER</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">TABLE</span><span style="color:#A6ACCD;"> 表名 ENGINE </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> 存储引擎名称;</span></span></code></pre></div><h2 id="阿里、京东等大厂都有自研的存储引擎-如何开发一套自己的" tabindex="-1">阿里、京东等大厂都有自研的存储引擎，如何开发一套自己的？ <a class="header-anchor" href="#阿里、京东等大厂都有自研的存储引擎-如何开发一套自己的" aria-label="Permalink to &quot;阿里、京东等大厂都有自研的存储引擎，如何开发一套自己的？&quot;">​</a></h2><p>开发存储引擎并不难，难的是开发出来高效的有意义的存储引擎。</p><p>简单例子可以看一下官方源码中的示例，可以实现一个什么也没做的存储引擎。</p><p>有兴趣可以参考官方文档：<a href="https://dev.mysql.com/doc/dev/mysql-server/latest/" target="_blank" rel="noreferrer">https://dev.mysql.com/doc/dev/mysql-server/latest/</a></p><h2 id="myisam-和-innodb-的区别是什么" tabindex="-1">MyISAM 和 InnoDB 的区别是什么 <a class="header-anchor" href="#myisam-和-innodb-的区别是什么" aria-label="Permalink to &quot;MyISAM 和 InnoDB 的区别是什么&quot;">​</a></h2><blockquote><p>重点：外键、事务、锁</p></blockquote><table><thead><tr><th><strong>对比项</strong></th><th><strong>MyISAM</strong></th><th><strong>InnoDB</strong></th></tr></thead><tbody><tr><td>外键</td><td>不支持</td><td>支持</td></tr><tr><td>事务</td><td>不支持</td><td>支持</td></tr><tr><td>行表锁</td><td>表锁，即使操作一条记录也会锁住整个表，不适合高并发的操作</td><td>行锁，操作时只锁某一行，不对其它行有影响，适合高并发的操作</td></tr><tr><td>缓存</td><td>只缓存索引，不缓存真实数据</td><td>不仅缓存索引还要缓存真实数据，对内存要求较高，而且内存大小对性能有决定性的影响</td></tr><tr><td>关注点</td><td>并发查询，节省资源、消耗少、简单业务</td><td>并发写、事务、多表关系、更大资源</td></tr><tr><td>默认安装</td><td>Y</td><td>Y</td></tr><tr><td>默认使用</td><td>N</td><td>Y</td></tr><tr><td>自带系统表使用</td><td>Y</td><td>N</td></tr></tbody></table><h2 id="如何选择存储引擎" tabindex="-1">如何选择存储引擎 <a class="header-anchor" href="#如何选择存储引擎" aria-label="Permalink to &quot;如何选择存储引擎&quot;">​</a></h2><blockquote><p>除非<strong>几乎没有写操作全部都是高频的读操作可以选择MyISAM作为表的存储引擎</strong></p><p>其他业务可以一律使用InnoDB。</p></blockquote><h1 id="mysql-事务-62-80" tabindex="-1">MySQL 事务 62-80 <a class="header-anchor" href="#mysql-事务-62-80" aria-label="Permalink to &quot;MySQL 事务 62-80&quot;">​</a></h1><h2 id="数据库事务-事务的特性" tabindex="-1">数据库事务？事务的特性 <a class="header-anchor" href="#数据库事务-事务的特性" aria-label="Permalink to &quot;数据库事务？事务的特性&quot;">​</a></h2><h3 id="_1-事务" tabindex="-1">1 事务 <a class="header-anchor" href="#_1-事务" aria-label="Permalink to &quot;1 事务&quot;">​</a></h3><blockquote><ul><li><p>是数据库操作的最小工作单元，是作为单个逻辑工作单元执行的一系列操作；</p></li><li><p>这些操作作为一个整体一起向系统提交，要么都执行、要么都不执行；</p></li><li><p>事务是一组不可再分割的操作集合（工作逻辑单元）事务都有 <strong>ACID</strong> 特性</p></li></ul></blockquote><h3 id="_2-什么是acid" tabindex="-1">2 什么是ACID？ <a class="header-anchor" href="#_2-什么是acid" aria-label="Permalink to &quot;2 什么是ACID？&quot;">​</a></h3><h4 id="_1-、原子性-atomicity" tabindex="-1"><strong>1 、原子性</strong> atomicity <a class="header-anchor" href="#_1-、原子性-atomicity" aria-label="Permalink to &quot;**1 、原子性**  atomicity&quot;">​</a></h4><blockquote><p><strong>过程的保证</strong>。<strong>只做一个步骤</strong> ：1 给钱、2 去买 、3 交回来</p><p>事务是数据库的逻辑工作单位，事务中包含的各操作<strong>要么都做，要么都不做</strong></p></blockquote><h4 id="_2-、一致性-consistency" tabindex="-1"><strong>2 、一致性</strong> consistency <a class="header-anchor" href="#_2-、一致性-consistency" aria-label="Permalink to &quot;**2 、一致性**  consistency&quot;">​</a></h4><blockquote><p><strong>结果的保证</strong>。<strong>保证要吃完</strong> 刚张嘴挂了，失去一致性</p></blockquote><blockquote><p>事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时，就说数据库处于一致性状态。如果数据库系统 运行中发生故障，有些事务尚未完成就被迫中断，这些未完成事务对数据库所做的修改有一部分已写入物理数据库，这时数据库就处于一种不正确的状态，或者说是不一致的状态。</p></blockquote><h4 id="_3-、隔离性-isolation" tabindex="-1"><strong>3 、隔离性</strong> isolation <a class="header-anchor" href="#_3-、隔离性-isolation" aria-label="Permalink to &quot;**3 、隔离性** isolation&quot;">​</a></h4><blockquote><p>并发事务互相干扰。<strong>不被干扰</strong> 刚张嘴别人塞了东西</p><p>一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的，并发执行的各个事务之间不能互相干扰。</p></blockquote><h4 id="_4-、持续性-永久性-durability" tabindex="-1">4 、持续性 永久性 durability <a class="header-anchor" href="#_4-、持续性-永久性-durability" aria-label="Permalink to &quot;4 、持续性 永久性 durability&quot;">​</a></h4><blockquote><p><strong>保存</strong> 吃到肚子里。也称永久性，指一个事务一旦提交，它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。</p></blockquote><h2 id="并发事务带来的问题⭐" tabindex="-1">并发事务带来的问题⭐ <a class="header-anchor" href="#并发事务带来的问题⭐" aria-label="Permalink to &quot;并发事务带来的问题⭐&quot;">​</a></h2><blockquote><p>多个事务并发执行一定会产生相互争夺资源的问题</p></blockquote><h3 id="脏读-dirty-read" tabindex="-1">脏读（Dirty read） <a class="header-anchor" href="#脏读-dirty-read" aria-label="Permalink to &quot;脏读（Dirty read）&quot;">​</a></h3><blockquote><p>是一个事务在处理过程中读取了另外一个事务未提交的数据。</p></blockquote><blockquote><p>当一个事务正在访问数据并且对其进行了修改，但是还没提交事务，这时另外一个事务也访问了这个数据，然后使用了这个数据，因为这个数据的修改还没提交到数据库，所以另外一个事务读取的数据就是“<strong>脏数据</strong>”，这种行为就是“<strong>脏读</strong>”，依据“<strong>脏数据</strong>”所做的操作可能是会出现问题的。</p></blockquote><h3 id="修改丢失-lost-of-modify" tabindex="-1">修改丢失（Lost of modify） <a class="header-anchor" href="#修改丢失-lost-of-modify" aria-label="Permalink to &quot;修改丢失（Lost of modify）&quot;">​</a></h3><blockquote><p><strong>修改丢失即覆盖</strong>。是指一个事务读取一个数据时，另外一个数据也访问了该数据，那么在第一个事务修改了这个数据之后，第二个事务也修改了这个数据。这样第一个事务内的修改结果就被丢失，这种情况就被称为修改丢失</p><p>比如数据库内字段值为18，一个事务要+5，另一个事务要+3，本来要加在一起的，即18+5+3=26，而现在是分别进行相加，18+5，18+3，这样最后结果只能是21或23，不会是26了，这就是丢失修改</p></blockquote><h3 id="不可重复读-unrepeatableread" tabindex="-1">不可重复读**（Unrepeatableread）** <a class="header-anchor" href="#不可重复读-unrepeatableread" aria-label="Permalink to &quot;不可重复读**（Unrepeatableread）**&quot;">​</a></h3><blockquote><p>指在一个事务内多<strong>次读取同一数据</strong>，在这个事务还没结束时，另外一个事务也访问了这个数据并<strong>对这个数据进行了修改</strong>，那么就可能造成<strong>第一个事务两次读取的数据不一致</strong>，这种情况就被称为不可重复读。</p></blockquote><h3 id="幻读-phantom-read" tabindex="-1">幻读（Phantom read） <a class="header-anchor" href="#幻读-phantom-read" aria-label="Permalink to &quot;幻读（Phantom read）&quot;">​</a></h3><blockquote><p>是指同一个事务内多次查询返回的<strong>结果集总数不一样</strong>（比如增加了或者减少了行记录）。</p></blockquote><blockquote><p>幻读与不可重复读类似，幻读是指一个事务<strong>读取了几行数据</strong>，这个事务还没结束，接着另外一个事务<strong>插入了一些数据</strong>，在随后的查询中，第一个事务读取到的数据就会<strong>比原本读取到的多</strong>，就好像发生了幻觉一样，所以称为幻读</p></blockquote><h3 id="不可重复读和幻读有什么区别" tabindex="-1">不可重复读和幻读有什么区别？ <a class="header-anchor" href="#不可重复读和幻读有什么区别" aria-label="Permalink to &quot;不可重复读和幻读有什么区别？&quot;">​</a></h3><blockquote><p>不可重复读 针对的是一份数据的修改</p><p>幻读 针对的是行数修改</p></blockquote><h2 id="mysql是如何避免事务并发问题的" tabindex="-1">MySQL是如何避免事务并发问题的？ <a class="header-anchor" href="#mysql是如何避免事务并发问题的" aria-label="Permalink to &quot;MySQL是如何避免事务并发问题的？&quot;">​</a></h2><blockquote><p>避免事务并发问题是需要付出性能代价的，此时和分布式系统设计一样（CAP定理及base理论），为了保证一致性就一定会牺牲性能，要做取舍</p></blockquote><blockquote><p>在mysql内部通过加锁的方式实现好了解决方案可供选择，就是配置事务隔离级别</p></blockquote><h3 id="_1-什么是事务隔离级别" tabindex="-1">1 什么是事务隔离级别 <a class="header-anchor" href="#_1-什么是事务隔离级别" aria-label="Permalink to &quot;1 什么是事务隔离级别&quot;">​</a></h3><div class="language-c"><button title="Copy Code" class="copy"></button><span class="lang">c</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">事务隔离级别                    脏读     不可重复读</span><span style="color:#89DDFF;">(</span><span style="color:#A6ACCD;">被修改</span><span style="color:#89DDFF;">)</span><span style="color:#A6ACCD;">    幻读（删减）</span></span>
<span class="line"><span style="color:#A6ACCD;">读未提交（read</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">uncommitted）    是        是            是</span></span>
<span class="line"><span style="color:#A6ACCD;">不可重复读（read</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">committed）    否        是            是</span></span>
<span class="line"><span style="color:#A6ACCD;">可重复读（repeatable</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">read）     否        否            是</span></span>
<span class="line"><span style="color:#A6ACCD;">串行化（serializable）          否        否            否</span></span></code></pre></div><h3 id="_2-默认的级别是什么" tabindex="-1">2 默认的级别是什么？ <a class="header-anchor" href="#_2-默认的级别是什么" aria-label="Permalink to &quot;2 默认的级别是什么？&quot;">​</a></h3><p><code>MySQL InnoDB</code>存储引擎默认的事务隔离级别是<strong>可重复读（REPEATABLE-READ）</strong></p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> @@tx_isolation; # MySQL </span><span style="color:#F78C6C;">5</span><span style="color:#A6ACCD;">.</span><span style="color:#F78C6C;">7</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> @@transaction_isolation; # MySQL </span><span style="color:#F78C6C;">8</span><span style="color:#A6ACCD;">.</span><span style="color:#F78C6C;">0</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301645925.png" alt="image-20221130164516828" style="zoom:80%;"><h3 id="_3-如何选择事务隔离级别" tabindex="-1">3 如何选择事务隔离级别？ <a class="header-anchor" href="#_3-如何选择事务隔离级别" aria-label="Permalink to &quot;3 如何选择事务隔离级别？&quot;">​</a></h3><blockquote><p>隔离级别越低，事务请求的锁越少相应性能也就越高，如没有特殊要求或有错误发生，使用默认的隔离级别即可，如果系统中有高频读写并且对一致性要求高那么就需要比较高的事务隔离级别甚至串行化。</p></blockquote><h2 id="靠缓存可以提升高事务隔离级别的性能吗" tabindex="-1">靠缓存可以提升高事务隔离级别的性能吗？ <a class="header-anchor" href="#靠缓存可以提升高事务隔离级别的性能吗" aria-label="Permalink to &quot;靠缓存可以提升高事务隔离级别的性能吗？&quot;">​</a></h2><blockquote><p>提升事务级别的目的本质是提供更高的数据一致性，如果前置有缓存，那么缓存只能提供高效读并不能保证数据及时一致性，相反的我们还需要对缓存管理有额外的开销。</p></blockquote><h2 id="mysql事务隔离是如何实现的" tabindex="-1">MySQL事务隔离是如何实现的？ <a class="header-anchor" href="#mysql事务隔离是如何实现的" aria-label="Permalink to &quot;MySQL事务隔离是如何实现的？&quot;">​</a></h2><blockquote><p>隔离的实现主要是读写锁和MVCC</p></blockquote><h3 id="_1-什么是一致性非锁定读和锁定读" tabindex="-1">1 什么是一致性非锁定读和锁定读？ <a class="header-anchor" href="#_1-什么是一致性非锁定读和锁定读" aria-label="Permalink to &quot;1 什么是一致性非锁定读和锁定读？&quot;">​</a></h3><h4 id="_1-锁定读" tabindex="-1">1 锁定读 <a class="header-anchor" href="#_1-锁定读" aria-label="Permalink to &quot;1 锁定读&quot;">​</a></h4><p>使用到了读写锁。读写锁是最简单直接的的事务隔离实现方式</p><blockquote><ul><li>每次读操作需要获取一个共享(读)锁，每次写操作需要获取一个写锁。</li><li>共享锁之间不会产生互斥，共享锁和写锁之间、以及写锁与写锁之间会产生互斥。</li><li>当产生锁竞争时，需要等待其中一个操作释放锁后，另一个操作才能获取到锁。</li></ul></blockquote><p>锁机制，解决的就是<strong>多个事务同时更新数据</strong>，此时必须要有一个加锁的机制</p><blockquote><ul><li>行锁（记录锁）：解决的就是<strong>多个事务同时更新一行数据</strong></li><li>间隙锁：解决的就是<strong>多个事务同时更新多行数据</strong></li></ul></blockquote><p>下列操作属于锁定读</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> ... lock </span><span style="color:#F78C6C;">in</span><span style="color:#A6ACCD;"> share mode</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> ... for </span><span style="color:#F78C6C;">update</span></span>
<span class="line"><span style="color:#F78C6C;">insert</span><span style="color:#A6ACCD;">、</span><span style="color:#F78C6C;">update</span><span style="color:#A6ACCD;">、</span><span style="color:#F78C6C;">delete</span></span></code></pre></div><h4 id="_2-非锁定读" tabindex="-1">2 非锁定读 <a class="header-anchor" href="#_2-非锁定读" aria-label="Permalink to &quot;2 非锁定读&quot;">​</a></h4><p>v10 -&gt; age=18</p><p>v11 -&gt;age=19</p><p>v12 -&gt;age=15</p><p>使用mvcc 多版本控制实现</p><h3 id="_2-说一下mvcc内部细节" tabindex="-1">2 说一下MVCC内部细节 <a class="header-anchor" href="#_2-说一下mvcc内部细节" aria-label="Permalink to &quot;2 说一下MVCC内部细节&quot;">​</a></h3><p><a href="https://dev.mysql.com/doc/refman/5.7/en/innodb-multi-versioning.html" target="_blank" rel="noreferrer">https://dev.mysql.com/doc/refman/5.7/en/innodb-multi-versioning.html</a></p><blockquote><p>Multi-Version Concurrency Control 多版本并发控制，<em>MVCC</em> 是一种并发控制的方法，一般在数据库管理系统中，实现对数据库的并发访问</p></blockquote><blockquote><p>InnoDB是一个多版本的存储引擎。它保存有关已更改行的旧版本的信息，以支持并发和回滚等事务特性。这些信息存储在一个称为回滚段的数据结构中的系统表空间或undo表空间中。参见第14.6.3.4节“撤消表空间”。InnoDB使用回滚段中的信息来执行事务回滚所需的撤消操作。它还使用这些信息构建行的早期版本，以实现一致的读取</p></blockquote><p>MVCC 的实现依赖于：隐藏字段、Read View、undo log</p><h4 id="_1-隐藏字段" tabindex="-1">1 隐藏字段 <a class="header-anchor" href="#_1-隐藏字段" aria-label="Permalink to &quot;1 隐藏字段&quot;">​</a></h4><blockquote><ul><li>A 6-byte <code>DB_TRX_ID</code> 用来标识最近一次对本行记录做修改 (insert 、update) 的事务的标识符 ，即最后一次修改本行记录的事务 id。 如果是 delete 操作， 在 InnoDB 存储引擎内部也属于一次 update 操作，即更新行中的一个特殊位 ，将行标识为己删除，并非真正删除。</li><li>A 7-byte <code>DB_ROLL_PTR</code> 回滚指针，指向该行的 undo log 。如果该行未被更新，则为空.</li><li>A 6-byte <code>DB_ROW_ID</code> 如果没有设置主键且该表没有唯一非空索引时，<code>InnoDB</code> 会使用该 id 来生成聚簇索引.</li></ul></blockquote><h4 id="_2-read-view" tabindex="-1">2 Read View <a class="header-anchor" href="#_2-read-view" aria-label="Permalink to &quot;2 Read View&quot;">​</a></h4><blockquote><p>不同的事务隔离级别中，当有事物在执行过程中修改了数据（更新版本号），在并发事务时需要判断一下版本链中的哪个版本是当前事务可见的。为此InnoDB有了ReadView的概念，使用ReadView来记录和隔离不同事务并发时此记录的哪些版本是对当前访问事物可见的。</p></blockquote><h4 id="_3-undo-log" tabindex="-1">3 undo log <a class="header-anchor" href="#_3-undo-log" aria-label="Permalink to &quot;3 undo log&quot;">​</a></h4><blockquote><p>除了用来回滚数据，还可以读取可见版本的数据。以此实现非锁定读</p></blockquote><h3 id="_3-mysql事务一致性-原子性是如何实现的" tabindex="-1">3 MySQL事务一致性，原子性是如何实现的？ <a class="header-anchor" href="#_3-mysql事务一致性-原子性是如何实现的" aria-label="Permalink to &quot;3 MySQL事务一致性，原子性是如何实现的？&quot;">​</a></h3><blockquote><p>首先是通过锁和mvcc实现了执行过程中的一致性和原子性</p><p>其次是在灾备方面通过Redo log实现，Redo log会把事务在执行过程中对数据库所做的所有修改都记录下来，在之后系统崩溃重启后可以把事务所做的任何修改都恢复出来。</p></blockquote><h3 id="_4-msql事务的持久性是如何实现的" tabindex="-1">4 MSQL事务的持久性是如何实现的 <a class="header-anchor" href="#_4-msql事务的持久性是如何实现的" aria-label="Permalink to &quot;4 MSQL事务的持久性是如何实现的&quot;">​</a></h3><blockquote><p>使用Redo log保证了事务的持久性。当事务提交时，必须先将事务的所有日志写入日志文件进行持久化，就是我们常说的WAL(write ahead log)机制，如果出现断电重启便可以从redolog中恢复，如果redolog写入失败那么也就意味着修改失败整个事务也就直接回滚了。</p></blockquote><h2 id="表级锁和行级锁有什么区别" tabindex="-1">表级锁和行级锁有什么区别？ <a class="header-anchor" href="#表级锁和行级锁有什么区别" aria-label="Permalink to &quot;表级锁和行级锁有什么区别？&quot;">​</a></h2><blockquote><p>表级锁：串行化（serializable）时，整表加锁，事务访问表数据时需要申请锁，虽然可分为读锁和写锁，但毕竟是锁住整张表，会导致并发能力下降，一般是做ddl处理时使用</p></blockquote><blockquote><p>行级锁：除了串行化（serializable）时 InnoDB使用的都是行级锁，只锁一行数据，并发能力强。</p></blockquote><h3 id="_1-什么是行级锁-mysql如何完成的" tabindex="-1">1 什么是行级锁？MySQL如何完成的？ <a class="header-anchor" href="#_1-什么是行级锁-mysql如何完成的" aria-label="Permalink to &quot;1 什么是行级锁？MySQL如何完成的？&quot;">​</a></h3><blockquote><p>行级锁实现比较复杂不是单纯锁住一行数据，是由mvcc完成的。</p></blockquote><h3 id="_2-什么是共享锁-读锁" tabindex="-1">2 什么是共享锁（读锁）？ <a class="header-anchor" href="#_2-什么是共享锁-读锁" aria-label="Permalink to &quot;2 什么是共享锁（读锁）？&quot;">​</a></h3><blockquote><p>共享锁或S锁，其它事务可以继续加共享锁，但不能加排它锁</p></blockquote><h3 id="_3-什么是排它锁-写锁-独占锁" tabindex="-1">3 什么是排它锁（写锁/独占锁）？ <a class="header-anchor" href="#_3-什么是排它锁-写锁-独占锁" aria-label="Permalink to &quot;3 什么是排它锁（写锁/独占锁）？&quot;">​</a></h3><blockquote><p>排它锁或X锁，在进行写操作之前要申请并获得，其它事务不能再获得任何锁。</p></blockquote><h3 id="_4-什么是意向锁" tabindex="-1">4 什么是意向锁？ <a class="header-anchor" href="#_4-什么是意向锁" aria-label="Permalink to &quot;4 什么是意向锁？&quot;">​</a></h3><p>它分为意向共享锁（IS）和意向排他锁（IX）</p><blockquote><p>一个事务对一张表的某行添加共享锁前，必须获得对该表一个IS锁或者优先级更高的锁。 一个事务对一张表的某行添加排他锁之前，它必须对该表获取一个IX锁。</p><p>意向锁属于表锁，它不与innodb中的行锁冲突，任意两个意向锁之间也不会产生冲突，但是会与表锁（S锁和X锁）产生冲突</p></blockquote><h3 id="_5-innodb支持哪几种锁" tabindex="-1">5 InnoDB支持哪几种锁？ <a class="header-anchor" href="#_5-innodb支持哪几种锁" aria-label="Permalink to &quot;5 InnoDB支持哪几种锁？&quot;">​</a></h3><p>表锁，行锁，间隙锁，Next-Key锁等</p><p>在Serializable中读加共享锁，写加排他锁，读写互斥</p><p>两段锁协议，将事务分成两个阶段，加锁阶段和解锁阶段（所以叫两段锁）</p><h2 id="当前读和快照读分别是什么" tabindex="-1">当前读和快照读分别是什么？ <a class="header-anchor" href="#当前读和快照读分别是什么" aria-label="Permalink to &quot;当前读和快照读分别是什么？&quot;">​</a></h2><p>当前读 ：在锁定读（使用锁隔离事物）的时候读到的是最新版本的数据</p><p>快照读：可重复读（repeatable-read）下 mvcc生效读取的是数据的快照，并不是最新版本的数据（未提交事物的数据）</p><h2 id="xa协议" tabindex="-1">XA协议 <a class="header-anchor" href="#xa协议" aria-label="Permalink to &quot;XA协议&quot;">​</a></h2><h3 id="_1-什么是xa协议" tabindex="-1">1 什么是XA协议 <a class="header-anchor" href="#_1-什么是xa协议" aria-label="Permalink to &quot;1 什么是XA协议&quot;">​</a></h3><p><a href="https://dev.mysql.com/doc/refman/8.0/en/xa.html" target="_blank" rel="noreferrer">https://dev.mysql.com/doc/refman/8.0/en/xa.html</a></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059908.png" alt="在这里插入图片描述" style="zoom:80%;"><blockquote><ul><li>AP（Application Program）：应用程序，定义事务边界（定义事务开始和结束）并访问事务边界内的资源。</li><li>RM（Resource Manger）资源管理器: 管理共享资源并提供外部访问接口。供外部程序来访问数据库等共享资源。此外，RM还具有事务的回滚能力。</li><li>TM（Transaction Manager）事务管理器：TM是分布式事务的协调者，TM与每个RM进行通信，负责管理全局事务，分配事务唯一标识，监控事务的执行进度，并负责事务的提交、回滚、失败恢复等。</li></ul></blockquote><blockquote><ul><li>应用程序AP向事务管理器TM发起事务请求</li><li>TM调用xa_open()建立同资源管理器的会话</li><li>TM调用xa_start()标记一个事务分支的开头</li><li>AP访问资源管理器RM并定义操作，比如插入记录操作</li><li>TM调用xa_end()标记事务分支的结束</li><li>TM调用xa_prepare()通知RM做好事务分支的提交准备工作。其实就是二阶段提交的提交请求阶段。</li><li>TM调用xa_commit()通知RM提交事务分支，也就是二阶段提交的提交执行阶段。</li><li>TM调用xa_close管理与RM的会话。 <ul><li>这些接口一定要按顺序执行，比如xa_start接口一定要在xa_end之前。此外，这里千万要注意的是事务管理器只是标记事务分支并不执行事务，事务操作最终是由应用程序通知资源管理器完成的。另外，我们来总结下XA的接口</li></ul></li><li>xa_start:负责开启或者恢复一个事务分支，并且管理XID到调用线程</li><li>xa_end:负责取消当前线程与事务分支的关系</li><li>xa_prepare:负责询问RM 是否准备好了提交事务分支 xa_commit:通知RM提交事务分支</li><li>xa_rollback:通知RM回滚事务分支</li></ul></blockquote><h3 id="_2-什么是mysql-xa事务" tabindex="-1">2 什么是MySQL XA事务？ <a class="header-anchor" href="#_2-什么是mysql-xa事务" aria-label="Permalink to &quot;2 什么是MySQL XA事务？&quot;">​</a></h3><p>mysql的xa事务分为两部分：</p><blockquote><ol><li>InnoDB内部本地普通事务操作协调数据写入与log写入两阶段提交</li><li>外部分布式事务</li></ol></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">5</span><span style="color:#A6ACCD;">.</span><span style="color:#F78C6C;">7</span><span style="color:#A6ACCD;"> SHOW VARIABLES </span><span style="color:#F78C6C;">LIKE</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%innodb_support_xa%</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#F78C6C;">8</span><span style="color:#A6ACCD;">.</span><span style="color:#F78C6C;">0</span><span style="color:#A6ACCD;"> 默认开启无法关闭</span></span></code></pre></div><p>XA 事务语法示例如下：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">XA </span><span style="color:#F78C6C;">START</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">自定义事务id</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">SQL语句...</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">XA </span><span style="color:#F78C6C;">END</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">自定义事务id</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">XA PREPARE </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">自定义事务id</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#A6ACCD;">XA </span><span style="color:#F78C6C;">COMMIT</span><span style="color:#A6ACCD;">\</span><span style="color:#F78C6C;">ROLLBACK</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">自定义事务id</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>XA PREPARE 执行成功后，事务信息将被持久化。即使会话终止甚至应用服务宕机，只要我们将【自定义事务id】记录下来，后续仍然可以使用它对事务进行 rollback 或者 commit。</p><h3 id="_3-xa事务与普通事务区别是什么" tabindex="-1">3 XA事务与普通事务区别是什么 <a class="header-anchor" href="#_3-xa事务与普通事务区别是什么" aria-label="Permalink to &quot;3 XA事务与普通事务区别是什么&quot;">​</a></h3><blockquote><p>xa事务可以跨库或跨服务器，属于分布式事务，同时xa事务还支撑了InnoDB内部日志两阶段记录</p><p>普通事务只能在单库中执行</p></blockquote><h3 id="_4-什么是2pc-3pc" tabindex="-1">4 什么是2pc 3pc <a class="header-anchor" href="#_4-什么是2pc-3pc" aria-label="Permalink to &quot;4 什么是2pc 3pc&quot;">​</a></h3><blockquote><p>两阶段提交协议与3阶段提交协议，额外增加了参与的角色保证分布式事务完成更完善</p></blockquote><h2 id="select-for-update-会产生哪些操作" tabindex="-1">select for update？会产生哪些操作？ <a class="header-anchor" href="#select-for-update-会产生哪些操作" aria-label="Permalink to &quot;select for update？会产生哪些操作？&quot;">​</a></h2><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">查询库存 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;">  </span><span style="color:#F78C6C;">0</span><span style="color:#A6ACCD;"> 扣减库存  </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">-</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">99</span></span>
<span class="line"><span style="color:#A6ACCD;">记录日志 </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">log</span></span>
<span class="line"><span style="color:#A6ACCD;">提交  </span><span style="color:#F78C6C;">commit</span></span></code></pre></div><blockquote><p>select本身是一个查询语句，查询语句是不会产生冲突的一种行为，一般情况下是没有锁的，用select for update 会让select语句产生一个排它锁(X), 这个锁和update的效果一样，会使两个事务无法同时更新一条记录。</p></blockquote><p><a href="https://dev.mysql.com/doc/refman/8.0/en/innodb-locks-set.html" target="_blank" rel="noreferrer">https://dev.mysql.com/doc/refman/8.0/en/innodb-locks-set.html</a></p><p><a href="https://dev.mysql.com/doc/refman/8.0/en/select.html" target="_blank" rel="noreferrer">https://dev.mysql.com/doc/refman/8.0/en/select.html</a></p><blockquote><ul><li><p>for update仅适用于InnoDB，且必须在事务块(BEGIN/COMMIT)中才能生效。</p></li><li><p>在进行事务操作时，通过“for update”语句，MySQL会对查询结果集中每行数据都添加排他锁，其他线程对该记录的更新与删除操作都会阻塞。排他锁包含行锁、表锁。</p></li><li><p><strong>InnoDB默认是行级别的锁，在筛选条件中当有明确指定主键或唯一索引列的时候，是行级锁。否则是表级别</strong></p></li></ul></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> … FOR </span><span style="color:#F78C6C;">UPDATE</span><span style="color:#A6ACCD;"> [OF column_list][WAIT n|NOWAIT][SKIP LOCKED];</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t for </span><span style="color:#F78C6C;">update</span><span style="color:#A6ACCD;"> 会等待行锁释放之后，返回查询结果。</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t for </span><span style="color:#F78C6C;">update</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">nowait</span><span style="color:#A6ACCD;"> 不等待行锁释放，提示锁冲突，不返回结果</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t for </span><span style="color:#F78C6C;">update</span><span style="color:#A6ACCD;"> wait </span><span style="color:#F78C6C;">5</span><span style="color:#A6ACCD;"> 等待5秒，若行锁仍未释放，则提示锁冲突，不返回结果</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> t for </span><span style="color:#F78C6C;">update</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">skip</span><span style="color:#A6ACCD;"> locked 查询返回查询结果，但忽略有行锁的记录</span></span></code></pre></div><h2 id="mysql死锁的原因和处理方法" tabindex="-1">MySQL死锁的原因和处理方法 <a class="header-anchor" href="#mysql死锁的原因和处理方法" aria-label="Permalink to &quot;MySQL死锁的原因和处理方法&quot;">​</a></h2><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">事务 a</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">表 t  id</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;"> 更新  加行锁</span></span>
<span class="line"><span style="color:#A6ACCD;">表 t  id</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">200</span><span style="color:#A6ACCD;"> 更新  已加锁</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">事务 b</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">表 t  id</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">200</span><span style="color:#A6ACCD;"> 更新 加行锁</span></span>
<span class="line"><span style="color:#A6ACCD;">表 t  id</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;"> 更新 已加锁</span></span></code></pre></div><p>死锁与锁等待是两个概念</p><ul><li><p>如未开启事务，多个客户端执行的insert操作</p></li><li><p>当多个事务同时持有和请求同一资源上的锁而产生循环依赖的时候就产生了死锁。</p></li></ul><p>排查：</p><p>正在运行的任务</p><ul><li>show full processlist; 找到卡主的进程</li></ul><p>解开死锁</p><ul><li>UNLOCK TABLES ；</li></ul><p>查看当前运行的事务</p><ul><li>SELECT * FROM information_schema.INNODB_TRX;</li></ul><p>当前出现的锁</p><ul><li>SELECT * FROM information_schema.INNODB_LOCKS;</li></ul><p>观察错误日志</p><p>查看InnoDB锁状态</p><ul><li><code>show status like &quot;innodb_row_lock%&quot;;</code></li></ul><blockquote><p>lnnodb_row_lock_current_waits:当前正在等待锁定的数量; lnnodb_row_lock_time :从系统启动到现在锁定的总时间长度，单位ms; Innodb_row_lock_time_avg :每次等待所花平均时间; Innodb_row_lock_time_max:从系统启动到现在等待最长的一次所花的时间; lnnodb_row_lock_waits :从系统启动到现在总共等待的次数。</p></blockquote><p>kill id 杀死进程</p><p>解决：</p><ul><li><p>死锁无法避免，上线前要进行严格的压力测试</p></li><li><p>快速失败</p><ul><li>innodb_lock_wait_timeout 行锁超时时间</li></ul></li><li><p>拆分sql，严禁大事务</p></li><li><p>充分利用索引，优化索引，尽量把有风险的事务sql使用上覆盖索，优化where条件前缀匹配，提升查询速度，引减少表锁</p></li><li><p>无法避免时：</p><ul><li>操作多张表时，尽量以相同的顺序来访问避免形成等待环路</li><li>单张表时先排序再操作</li><li>使用排它锁 比如 for update</li></ul></li></ul><h2 id="mysql日志" tabindex="-1">MySQL日志 <a class="header-anchor" href="#mysql日志" aria-label="Permalink to &quot;MySQL日志&quot;">​</a></h2><h3 id="_1-错误日志-error-log" tabindex="-1">1 错误日志（error log） <a class="header-anchor" href="#_1-错误日志-error-log" aria-label="Permalink to &quot;1 错误日志（error log）&quot;">​</a></h3><blockquote><p>error log主要记录MySQL<strong>在启动、关闭或者运行过程中的错误信息</strong></p><p>在MySQL的配置文件my.cnf中，可以通过<strong>log-error=/var/log/mysqld.log</strong> 执行mysql错误日志的位置。</p></blockquote><h3 id="_2-慢查询日志-slow-query-log" tabindex="-1">2 慢查询日志（slow query log） <a class="header-anchor" href="#_2-慢查询日志-slow-query-log" aria-label="Permalink to &quot;2 慢查询日志（slow query log）&quot;">​</a></h3><blockquote><p>MySQL的慢查询日志是MySQL提供的一种日志记录，它用来记录在MySQL中响应时间超过阀值的语句，具体指运行时间超过long_query_time值的SQL，则会被记录到慢查询日志中。</p></blockquote><blockquote><p><strong>long_query_time的默认值为10，意思是运行10秒以上的语句。</strong></p></blockquote><blockquote><p>由他来查看哪些SQL超出了我们的最大忍耐时间值，比如一条sql执行超过5秒钟，我们就算慢SQL，希望能收集超过5秒的sql，结合之前explain进行全面分析。</p></blockquote><blockquote><p>默认情况下，MySQL数据库没有开启慢查询日志，需要我们手动来设置这个参数。</p></blockquote><blockquote><p>当然，如果不是调优需要的话，一般不建议启动该参数，因为开启慢查询日志会或多或少带来一定的性能影响。慢查询<strong>日志支持将日志记录写入文件</strong>。</p></blockquote><blockquote><p>在生产环境中，如果要手工分析日志，查找、分析SQL，显然是个体力活，MySQL提供了日志分析工具mysqldumpslow。</p></blockquote><h3 id="_3-一般查询日志-general-log" tabindex="-1">3 一般查询日志（general log） <a class="header-anchor" href="#_3-一般查询日志-general-log" aria-label="Permalink to &quot;3 一般查询日志（general log）&quot;">​</a></h3><p>general log 记录了客户端连接信息以及执行的SQL语句信息</p><ul><li><p><strong>重写日志（redo log）</strong></p></li><li><p><strong>回滚日志（undo log）</strong></p></li><li><p><strong>二进制日志（bin log）</strong></p></li></ul><h3 id="_4-bin-log作用是什么" tabindex="-1">4 bin log作用是什么 <a class="header-anchor" href="#_4-bin-log作用是什么" aria-label="Permalink to &quot;4 bin log作用是什么&quot;">​</a></h3><blockquote><p>MySQL的bin log日志是用来记录MySQL中增删改时的记录日志。当你的一条sql操作对数据库中的内容进行了更新，就会增加一条bin log日志。查询操作不会记录到bin log中。</p></blockquote><blockquote><p>bin log最大的用处就是进行<strong>主从复制，以及数据库的恢复。</strong></p></blockquote><h3 id="_5-redo-log作用是什么" tabindex="-1">5 redo log作用是什么 <a class="header-anchor" href="#_5-redo-log作用是什么" aria-label="Permalink to &quot;5 redo log作用是什么&quot;">​</a></h3><blockquote><p>redo log是一种基于磁盘的数据结构，用来在MySQL宕机情况下将不完整的事务执行数据纠正，redo日志记录事务执行后的状态。</p></blockquote><blockquote><p>当事务开始后，redo log就开始产生，并且随着事务的执行不断写入redo log file中。redo log file中记录了xxx页做了xx修改的信息，我们都知道数据库的更新操作会在内存中先执行，最后刷入磁盘。</p></blockquote><blockquote><p>redo log就是为了恢复更新了内存但是由于宕机等原因没有刷入磁盘中的那部分数据。</p></blockquote><h3 id="_6-undo-log作用是什么" tabindex="-1">6 undo log作用是什么 <a class="header-anchor" href="#_6-undo-log作用是什么" aria-label="Permalink to &quot;6 undo log作用是什么&quot;">​</a></h3><blockquote><p>undo log主要用来回滚到某一个版本，是一种逻辑日志。</p></blockquote><blockquote><p>undo log<strong>记录的是修改之前的数据</strong>，比如：当delete一条记录时，undolog中会记录一条对应的insert记录，从而保证能恢复到数据修改之前。在执行事务回滚的时候，就可以通过undo log中的记录内容并以此进行回滚。</p></blockquote><blockquote><p>undo log还可以提供多版本并发控制下的读取（MVCC）。<strong>读取老版本数据</strong></p></blockquote><h3 id="_7-mysql日志是否实时写入磁盘" tabindex="-1">7 MySQL日志是否实时写入磁盘？ <a class="header-anchor" href="#_7-mysql日志是否实时写入磁盘" aria-label="Permalink to &quot;7 MySQL日志是否实时写入磁盘？&quot;">​</a></h3><blockquote><p>磁盘写入固然是比较慢的。参数：sync_binlog</p></blockquote><p>binlog 写入策略：</p><blockquote><p><strong>1、sync_binlog=0</strong> 的时候，表示每次提交事务binlog不会马上写入到磁盘，而是先写到page cache,相对于磁盘写入来说写page cache要快得多,不过在Mysql 崩溃的时候会有丢失日志的风险。</p><p><strong>2、sync_binlog=1</strong> 的时候，表示每次提交事务都会执行 fsync 写入到磁盘 ；</p><p><strong>3、sync_binlog的值大于1</strong> 的时候，表示每次提交事务都 先写到page cach，只有等到积累了N个事务之后才fsync 写入到磁盘，同样在此设置下Mysql 崩溃的时候会有丢失N个事务日志的风险。</p></blockquote><blockquote><p>很显然三种模式下，sync_binlog=1 是强一致的选择，选择0或者N的情况下在极端情况下就会有丢失日志的风险，具体选择什么模式还是得看系统对于一致性的要求。</p></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059820.png" alt="img" style="zoom:80%;"><p><strong>innodb_flush_log_at_trx_commit</strong></p><blockquote><ul><li>取值0：每秒（一秒钟内提交的事务）写入磁盘 每秒触发一次缓存日志回写磁盘操作，并调用操作系统fsync刷新IO缓存。</li><li>取值1：有事务提交就立即刷盘 每次提交事务都立即调用操作系统fsync刷新IO缓存。</li><li>取值2：每次事务提交 都写给操作系统 由系统接管什么时候写入磁盘 每次都把redo log写到系统的page cache中，由系统接管什么时候写入磁盘</li></ul></blockquote><p>时机顺序：</p><blockquote><ul><li><p>1 开启事务</p></li><li><p>2 查询数据库中需要更新的字段，加载到内存中 形成数据<strong>脏页</strong></p></li><li><p>3 记录undo log到内存缓冲区（用于回滚和mvcc）并关联redo log -&gt; 可刷盘</p></li><li><p>4 记录 redo log到内存缓冲区 （用于失败重放）准备提交事务 -&gt; 可刷盘</p></li><li><p>5 修改内存中的脏页数据</p></li><li><p>6 提交事务触发redolog刷盘</p></li><li><p>7 undo log 和脏页 刷盘</p></li><li><p>8 事务成功</p></li></ul></blockquote><p><strong>redo log 与 binlog 的两阶段提交</strong></p><p>redo log 的写入拆成了两个步骤：prepare 和 commit</p><blockquote><ul><li><p><strong>prepare</strong>：redolog写入log buffer，并fsync持久化到磁盘，在redolog事务中记录2PC的XID，在redolog事务打上prepare标识</p></li><li><p><strong>commit</strong>：binlog写入log buffer，并fsync持久化到磁盘，在binlog事务中记录2PC的XID，同时在redolog事务打上commit标识</p></li></ul></blockquote><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059943.jpg" alt="img" style="zoom:80%;"><h3 id="_8-binlog有几种格式" tabindex="-1">8 binlog有几种格式 <a class="header-anchor" href="#_8-binlog有几种格式" aria-label="Permalink to &quot;8 binlog有几种格式&quot;">​</a></h3><blockquote><p>binlog_format=STATEMENT（默认）：数据操作的时间，同步时不一致 每一条会修改数据的sql语句会记录到binlog中。优点是并不需要记录每一 条sql语句和每一行的 数据变化，减少了binlog日志量，节约IO，提高性能。缺点是在某些情况下会导致 master-slave 中的数据不一致( 如sleep()函数， last_insert_id()，以及user-defined functions(udf)等会出现 问题)</p></blockquote><blockquote><p>binlog_format=ROW：批量数据操作时，效率低 不记录每条sql语句的上下文信息，仅需记录哪条数据被修改了，修改成什么样 了。而且不会出 现某些特定情况下的存储过程、或function、或trigger的调用和触发无法被正确复制的 问题。缺 点是会产生大量的日志，尤其是alter table的时候会让日志暴涨。</p></blockquote><blockquote><p>binlog_format=MIXED：是以上两种level的混合使用，有函数用ROW，没函数用STATEMENT，但无法识别系统变量</p></blockquote><h3 id="_9-mysql集群同步为什么使用binlog" tabindex="-1">9 MySQL集群同步为什么使用binlog <a class="header-anchor" href="#_9-mysql集群同步为什么使用binlog" aria-label="Permalink to &quot;9 MySQL集群同步为什么使用binlog&quot;">​</a></h3><blockquote><ul><li>binlog是mysql提供的日志，所有存储引擎都可用。</li><li>支持增量同步</li><li>binlog还可以供其他中间件读取，比如同步到hdfs中</li></ul></blockquote><blockquote><p>如果复制表数据：不支持某个阶段回放,直接复制数据过程中一旦中断复制（比如断网），很难确定复制的offset</p></blockquote><h1 id="mysql-开发⭐-81-102" tabindex="-1">MySQL 开发⭐ 81-102 <a class="header-anchor" href="#mysql-开发⭐-81-102" aria-label="Permalink to &quot;MySQL 开发⭐ 81-102&quot;">​</a></h1><h2 id="可以使用mysql直接存储文件吗" tabindex="-1">可以使用MySQL直接存储文件吗？ <a class="header-anchor" href="#可以使用mysql直接存储文件吗" aria-label="Permalink to &quot;可以使用MySQL直接存储文件吗？&quot;">​</a></h2><h3 id="_1-文件存储类型" tabindex="-1">1 文件存储类型 <a class="header-anchor" href="#_1-文件存储类型" aria-label="Permalink to &quot;1 文件存储类型&quot;">​</a></h3><p>可以使用 BLOB (binary large object)，用来存储二进制大对象的字段类型。</p><blockquote><ul><li>TinyBlob 255 值的长度加上用于记录长度的1个字节(8位)</li><li>Blob 65K值的长度加上用于记录长度的2个字节(16位)</li><li>MediumBlob 16M值的长度加上用于记录长度的3个字节(24位)</li><li>LongBlob 4G 值的长度加上用于记录长度的4个字节(32位)。</li></ul></blockquote><h3 id="_2-什么时候存-什么时候不存" tabindex="-1">2 什么时候存，什么时候不存？ <a class="header-anchor" href="#_2-什么时候存-什么时候不存" aria-label="Permalink to &quot;2 什么时候存，什么时候不存？&quot;">​</a></h3><blockquote><p>存：需要高效查询并且文件很小的时候</p><p>不存：文件比较大，数据量多或变更频繁的时候</p></blockquote><h3 id="_3-存储的时候有遇到过什么问题吗" tabindex="-1">3 存储的时候有遇到过什么问题吗？ <a class="header-anchor" href="#_3-存储的时候有遇到过什么问题吗" aria-label="Permalink to &quot;3 存储的时候有遇到过什么问题吗？&quot;">​</a></h3><blockquote><ol><li>上传数据过大sql执行失败 调整max_allowed_packet</li><li>主从同步数据时比较慢</li><li>应用线程阻塞</li><li>占用网络带宽</li><li>高频访问的图片无法使用浏览器缓存</li></ol></blockquote><h3 id="_4-emoji乱码怎么办" tabindex="-1">4 Emoji乱码怎么办？ <a class="header-anchor" href="#_4-emoji乱码怎么办" aria-label="Permalink to &quot;4 Emoji乱码怎么办？&quot;">​</a></h3><blockquote><p>数据库编码使用utf8mb4。MySQL在5.5.3之后增加了这个utf8mb4的编码，mb4就是most bytes 4的意思，专门用来兼容四字节的unicode。好在utf8mb4是utf8的超集，除了将编码改为utf8mb4外不需要做其他转换。当然，一般情况下使用utf8也就够了。</p></blockquote><h2 id="如何存储ip地址" tabindex="-1">如何存储ip地址？ <a class="header-anchor" href="#如何存储ip地址" aria-label="Permalink to &quot;如何存储ip地址？&quot;">​</a></h2><blockquote><ul><li>使用字符串 或者 <strong>使用无符号整型</strong></li><li>4个字节即解决问题</li><li>可以支持范围查询</li><li><strong>INET_ATON()</strong> 和 <strong>INET_NTOA()</strong> ipv6 使用 <strong>INET6_ATON()</strong> 和 <strong>INET6_NTOA()</strong></li></ul></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> inet_aton(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">192.168.22.130</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">) </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">IP转数字</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">, inet_ntoa(</span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">3232241282</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">) </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">数字转IP</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2023.1.30/202212311543266.png" alt="image-20221231154334194" style="zoom:80%;"><h2 id="长文本如何存储" tabindex="-1">长文本如何存储？ <a class="header-anchor" href="#长文本如何存储" aria-label="Permalink to &quot;长文本如何存储？&quot;">​</a></h2><blockquote><p>可以使用Text存储，text创建索引要指定长度，同时不支持默认值</p><p><strong>TINYTEXT(255长度)</strong></p><p><strong>TEXT(65535)</strong></p><p><strong>MEDIUMTEXT（int最大值16M）</strong></p><p><strong>LONGTEXT(long最大值4G)</strong></p></blockquote><h2 id="大段文本如何设计表结构" tabindex="-1">大段文本如何设计表结构？ <a class="header-anchor" href="#大段文本如何设计表结构" aria-label="Permalink to &quot;大段文本如何设计表结构？&quot;">​</a></h2><h3 id="_1-如何存储大段文本" tabindex="-1">1 如何存储大段文本 <a class="header-anchor" href="#_1-如何存储大段文本" aria-label="Permalink to &quot;1 如何存储大段文本&quot;">​</a></h3><blockquote><ol><li>或将大段文本同时存储到ES搜索引擎</li><li>分表存储</li><li>分表后多段存储</li></ol></blockquote><h3 id="_2-大段文本查找时如何建立索引" tabindex="-1">2 大段文本查找时如何建立索引？ <a class="header-anchor" href="#_2-大段文本查找时如何建立索引" aria-label="Permalink to &quot;2 大段文本查找时如何建立索引？&quot;">​</a></h3><blockquote><ol><li>全文检索，模糊匹配最好存储到搜索引擎中</li><li><strong>指定索引长度</strong></li><li>分段存储后创建索引</li></ol></blockquote><h3 id="_3-开发中使用过text-blob-数据类型吗" tabindex="-1">3 开发中使用过TEXT,BLOB 数据类型吗 <a class="header-anchor" href="#_3-开发中使用过text-blob-数据类型吗" aria-label="Permalink to &quot;3 开发中使用过TEXT,BLOB 数据类型吗&quot;">​</a></h3><blockquote><p>BLOB 之前做ERP的时候使用过，互联网项目一般不用BLOB</p><p>TEXT 文献，文章，小说类，新闻，会议内容 等</p></blockquote><h2 id="日期相关问题" tabindex="-1">日期相关问题 <a class="header-anchor" href="#日期相关问题" aria-label="Permalink to &quot;日期相关问题&quot;">​</a></h2><h3 id="_1-日期-时间如何存取" tabindex="-1">1 日期，时间如何存取？ <a class="header-anchor" href="#_1-日期-时间如何存取" aria-label="Permalink to &quot;1 日期，时间如何存取？&quot;">​</a></h3><blockquote><ol><li>使用 TIMESTAMP，DATETIME</li><li>使用字符串</li></ol></blockquote><h3 id="_2-timestamp-datetime-的区别" tabindex="-1">2 TIMESTAMP，DATETIME 的区别 <a class="header-anchor" href="#_2-timestamp-datetime-的区别" aria-label="Permalink to &quot;2 TIMESTAMP，DATETIME 的区别&quot;">​</a></h3><blockquote><p>跨时区的业务使用 TIMESTAMP，TIMESTAMP会有时区转换</p></blockquote><h4 id="_1、两者的存储方式不一样" tabindex="-1">1、两者的存储方式不一样 <a class="header-anchor" href="#_1、两者的存储方式不一样" aria-label="Permalink to &quot;1、两者的存储方式不一样&quot;">​</a></h4><blockquote><p>对于TIMESTAMP，它把客户端插入的时间从当前时区转化为UTC（世界标准时间）进行存储。查询时，将其又转化为客户端当前时区进行返回。</p><p>而对于DATETIME，不做任何改变，基本上是原样输入和输出。</p></blockquote><h4 id="_2、存储字节大小不同" tabindex="-1">2、存储字节大小不同 <a class="header-anchor" href="#_2、存储字节大小不同" aria-label="Permalink to &quot;2、存储字节大小不同&quot;">​</a></h4><table><thead><tr><th>数据类型</th><th>MySQL 5.6.4之前需要存储</th><th>MySQL 5.6.4之后需要存储</th></tr></thead><tbody><tr><td>DATETIME</td><td>8 bytes</td><td>5 bytes + 小数秒存储</td></tr><tr><td>TIMESTAMP</td><td>4 bytes</td><td>4 bytes + 小数秒存储</td></tr></tbody></table><table><thead><tr><th>分秒数精度</th><th>存储字节大小</th></tr></thead><tbody><tr><td>0</td><td>0 bytes</td></tr><tr><td>1,2</td><td>1 bytes</td></tr><tr><td>3,4</td><td>2 bytes</td></tr><tr><td>5,6</td><td>3 bytes</td></tr></tbody></table><h4 id="_3、两者所能存储的时间范围不一样" tabindex="-1">3、两者所能存储的时间范围不一样 <a class="header-anchor" href="#_3、两者所能存储的时间范围不一样" aria-label="Permalink to &quot;3、两者所能存储的时间范围不一样&quot;">​</a></h4><blockquote><ul><li>timestamp所能存储的时间范围为：&#39;1970-01-01 00:00:01.000000&#39; 到 &#39;2038-01-19 03:14:07.999999&#39;。</li><li>datetime所能存储的时间范围为：&#39;1000-01-01 00:00:00.000000&#39; 到 &#39;9999-12-31 23:59:59.999999&#39;。</li></ul></blockquote><h3 id="_3为什么不使用字符串存储日期" tabindex="-1">3 为什么不使用字符串存储日期？ <a class="header-anchor" href="#_3为什么不使用字符串存储日期" aria-label="Permalink to &quot;3	为什么不使用字符串存储日期？&quot;">​</a></h3><blockquote><p><strong>字符串无法完成数据库内部的范围筛选</strong></p><p><strong>在大数据量存储优化索引时，查询必须加上时间范围</strong></p></blockquote><h3 id="_4时间戳-timestamp和int该如何选择" tabindex="-1">4 时间戳 timestamp和int该如何选择 <a class="header-anchor" href="#_4时间戳-timestamp和int该如何选择" aria-label="Permalink to &quot;4	时间戳 timestamp和int该如何选择&quot;">​</a></h3><blockquote><p><strong>int</strong> 存储空间小，运算查询效率高，不受时区影响，精度低</p><p><strong>timestamp</strong> 存储空间小，可以使用数据库内部时间函数比如更新，精度高，需要注意时区转换，timestamp更易读</p><p>一般选择timestamp，两者性能差异不明显，本质上存储都是使用的int</p></blockquote><h2 id="char与varchar的区别-如何选择" tabindex="-1">char与varchar的区别？如何选择？ <a class="header-anchor" href="#char与varchar的区别-如何选择" aria-label="Permalink to &quot;char与varchar的区别？如何选择？&quot;">​</a></h2><blockquote><p>1.char的优点是存储空间固定（最大255），没有碎片，尤其更新比较频繁的时候，方便数据文件指针的操作，所以存储读取速度快。缺点是空间冗余，对于数据量大的表，非固定长度属性使用char字段，空间浪费。</p><p>2.varchar字段，存储的空间根据存储的内容变化，空间长度为L+size，存储内容长度加描述存储内容长度信息，优点就是空间节约，缺点就是读取和存储时候，需要读取信息计算下标，才能获取完整内容。</p></blockquote><h2 id="财务计算有没有出现过错乱" tabindex="-1">财务计算有没有出现过错乱？ <a class="header-anchor" href="#财务计算有没有出现过错乱" aria-label="Permalink to &quot;财务计算有没有出现过错乱？&quot;">​</a></h2><blockquote><p>第一类：锁包括多线程，数据库，UI展示后超时提交等</p><p>第二类：应用与数据库浮点运算精度丢失</p></blockquote><blockquote><ol><li>应用开发问题：多线程共享数据读写，</li><li>之前有过丢失精度的问题，使用decimal解决</li><li>使用乘法替换除法</li><li>使用事务保证acid特性</li><li>更新时使用悲观锁 SELECT … FOR UPDATE</li><li>数据只有标记删除</li><li>记录详细日志方便溯源</li></ol></blockquote><h2 id="decimal与float-double的区别是什么" tabindex="-1">decimal与float,double的区别是什么？ <a class="header-anchor" href="#decimal与float-double的区别是什么" aria-label="Permalink to &quot;decimal与float,double的区别是什么？&quot;">​</a></h2><h3 id="_1-浮点型类型" tabindex="-1">1 浮点型类型 <a class="header-anchor" href="#_1-浮点型类型" aria-label="Permalink to &quot;1 浮点型类型&quot;">​</a></h3><blockquote><p>float：浮点型，4字节，32bit。</p><p>double：双精度实型，8字节，64位</p><p>decimal：数字型，128bit，不存在精度损失⭐</p></blockquote><p>对于声明语法DECIMAL(M,D)，自变量的值范围如下：</p><blockquote><ul><li>M是最大位数（精度），范围是1到65。可不指定，默认值是10。</li><li>D是小数点右边的位数（小数位）。范围是0到30，并且不能大于M，可不指定，默认值是0。</li></ul></blockquote><blockquote><p>例如字段 salary DECIMAL(5,2)，能够存储具有五位数字和两位小数的任何值，因此可以存储在salary列中的值的范围是从-999.99到999.99。</p></blockquote><h3 id="_2-浮点类型如何选型-为什么" tabindex="-1">2 浮点类型如何选型？为什么？ <a class="header-anchor" href="#_2-浮点类型如何选型-为什么" aria-label="Permalink to &quot;2 浮点类型如何选型？为什么？&quot;">​</a></h3><blockquote><ul><li><p>需要<strong>不丢失精度</strong>的计算使用<strong>DECIMAL</strong></p></li><li><p>仅用于展示没有计算的小数存储可以使用字符串存储</p></li><li><p>低价值数据允许计算后丢失精度可以使用float double</p></li><li><p>整型记录不会出现小数的不要使用浮点类型</p></li></ul></blockquote><h2 id="预编译sql好处" tabindex="-1">预编译SQL好处 <a class="header-anchor" href="#预编译sql好处" aria-label="Permalink to &quot;预编译SQL好处&quot;">​</a></h2><p>完整解释：PreparedStatement</p><p><a href="https://dev.mysql.com/doc/refman/8.0/en/prepare.html" target="_blank" rel="noreferrer">https://dev.mysql.com/doc/refman/8.0/en/prepare.html</a></p><blockquote><ul><li>预编译sql会被mysql缓存下来</li><li>作用域是每个session，对其他session无效，重新连接也会失效</li><li>提高安全性防止sql注入，不会把传入的delete...SQL当成正常的SQL执行 <ul><li>select * from user where id =?</li><li>将?表示成：&quot;1;delete from user where id = 1&quot;;，会导致SQL注入风险</li></ul></li><li>编译语句有可能被重复调用，也就是说sql相同参数不同在同一session中重复查询执行效率明显比较高</li><li>mysql 5,8 支持服务器端的预编译</li></ul></blockquote><h2 id="子查询与join" tabindex="-1">子查询与join <a class="header-anchor" href="#子查询与join" aria-label="Permalink to &quot;子查询与join&quot;">​</a></h2><blockquote><p>子查询虽然很灵活，但是执行效率并不高。</p></blockquote><h3 id="_1-为什么子查询效率低" tabindex="-1">1 为什么子查询效率低？ <a class="header-anchor" href="#_1-为什么子查询效率低" aria-label="Permalink to &quot;1 为什么子查询效率低？&quot;">​</a></h3><blockquote><p>在执行子查询的时候，MYSQL创建了临时表，查询完毕后再删除这些临时表</p></blockquote><blockquote><p>子查询的速度慢的原因是多了一个创建和销毁临时表的过程。而join 则不需要创建临时表 所以会比子查询快一点</p></blockquote><h3 id="_2-join查询可以无限叠加吗" tabindex="-1">2 join查询可以无限叠加吗？ <a class="header-anchor" href="#_2-join查询可以无限叠加吗" aria-label="Permalink to &quot;2 join查询可以无限叠加吗？&quot;">​</a></h3><blockquote><p>建议join不超过3张表关联，mysql对内存敏感，关联过多会占用更多内存空间，使性能下降</p></blockquote><blockquote><p>Too many tables; MySQL can only use 61 tables in a join；系统限制最多关联61个表</p></blockquote><h3 id="_3-join-查询算法了解吗" tabindex="-1">3 join 查询算法了解吗？ <a class="header-anchor" href="#_3-join-查询算法了解吗" aria-label="Permalink to &quot;3  join 查询算法了解吗？&quot;">​</a></h3><blockquote><ul><li>Simple Nested-Loop Join：SNLJ，<strong>简单嵌套</strong>循环连接</li><li>Index Nested-Loop Join：INLJ，<strong>索引嵌套</strong>循环连接</li><li>Block Nested-Loop Join：BNLJ，<strong>缓存块嵌套</strong>循环连接</li></ul></blockquote><h3 id="_4-如何优化过多join查询关联" tabindex="-1">4 如何优化过多join查询关联？ <a class="header-anchor" href="#_4-如何优化过多join查询关联" aria-label="Permalink to &quot;4 如何优化过多join查询关联？&quot;">​</a></h3><blockquote><ul><li>适当使用冗余字段减少多表关联查询</li><li>驱动表和被驱动表（小表join大表）</li><li>业务允许的话 尽量使用inner join 让系统帮忙自动选择驱动表</li><li>关联字段一定创建索引</li><li>调整JOIN BUFFER大小，1G，4G...</li></ul></blockquote><h2 id="是否有过mysql调优经验" tabindex="-1">是否有过MySQL调优经验？ <a class="header-anchor" href="#是否有过mysql调优经验" aria-label="Permalink to &quot;是否有过MySQL调优经验？&quot;">​</a></h2><blockquote><ol><li>SQL调优</li><li>表（结构）设计调优</li><li>索引调优</li><li>慢查询调优</li><li>操作系统调优</li><li>数据库参数调优</li></ol></blockquote><h3 id="_1-开发中使用过哪些调优工具" tabindex="-1">1 开发中使用过哪些调优工具？ <a class="header-anchor" href="#_1-开发中使用过哪些调优工具" aria-label="Permalink to &quot;1 开发中使用过哪些调优工具？&quot;">​</a></h3><p>官方自带：</p><blockquote><ul><li>EXPLAIN</li><li>mysqldumpslow</li><li>show profiles 时间</li><li>optimizer_trace 优化器选择策略</li></ul></blockquote><blockquote><p>第三方：性能诊断工具，参数扫描提供建议，参数辅助优化</p></blockquote><h3 id="_2-如何监控线上环境中执行比较慢的sql" tabindex="-1">2 如何监控线上环境中执行比较慢的sql <a class="header-anchor" href="#_2-如何监控线上环境中执行比较慢的sql" aria-label="Permalink to &quot;2 如何监控线上环境中执行比较慢的sql&quot;">​</a></h3><blockquote><ul><li><p>开启慢查询日志，收集SQL</p></li><li><p>默认情况下，MySQL数据库没有开启慢查询日志，需要我们手动来设置这个参数。</p></li><li><p>当然，如果不是调优需要的话，一般不建议启动该参数，因为开启慢查询日志会或多或少带来一定的性能影响。慢查询<strong>日志支持将日志记录写入文件</strong>。</p></li></ul></blockquote><h3 id="_3-查看及开启慢sql" tabindex="-1">3 查看及开启慢SQL <a class="header-anchor" href="#_3-查看及开启慢sql" aria-label="Permalink to &quot;3 查看及开启慢SQL&quot;">​</a></h3><p>默认关闭</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">SHOW VARIABLES </span><span style="color:#F78C6C;">LIKE</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%slow_query_log%</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>默认情况下slow_query_log的值为OFF，表示慢查询日志是禁用的，</p><p>开启：<code>set global slow_query_log=1;</code> 只对窗口生效，重启服务失效</p><p>慢查询日志记录long_query_time时间</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">SHOW VARIABLES </span><span style="color:#F78C6C;">LIKE</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%long_query_time%</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">SHOW </span><span style="color:#F78C6C;">GLOBAL</span><span style="color:#A6ACCD;"> VARIABLES </span><span style="color:#F78C6C;">LIKE</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">long_query_time</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>全局变量设置，对所有客户端有效。但，必须是设置后进行登录的客户端。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">SET</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">GLOBAL</span><span style="color:#A6ACCD;"> long_query_time</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">0</span><span style="color:#A6ACCD;">.</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>对当前会话连接立即生效，对其他客户端无效。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">SET</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">SESSION</span><span style="color:#A6ACCD;"> long_query_time</span><span style="color:#89DDFF;">=</span><span style="color:#F78C6C;">0</span><span style="color:#A6ACCD;">.</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">; #session可省略</span></span></code></pre></div><p>假如运行时间正好等于long_query_time的情况，并不会被记录下来。也就是说，</p><p>在mysql源码里是判断大于long_query_time，而非大于等于。</p><ol><li><p>永久生效</p></li><li><p>修改配置文件my.cnf（其它系统变量也是如此）</p><p>[mysqld]下增加或修改参数</p><p>slow_query_log 和slow_query_log_file后，然后重启MySQL服务器。也即将如下两行配置进my.cnf文件</p></li></ol><p>slow_query_log =1</p><p>slow_query_log_file=/var/lib/mysql/localhost-slow.log</p><p>long_query_time=3</p><p>log_output=FILE</p><p>关于慢查询的参数slow_query_log_file，它指定慢查询日志文件的存放路径，如果不设置，系统默认文件：[host_name]-slow.log</p><p>记录慢SQL并后续分析</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> emp;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> emp </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> deptid </span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>查询当前系统中有多少条慢查询记录或者直接看慢查询日志</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">var</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">lib</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">mysql</span><span style="color:#89DDFF;">/</span><span style="color:#A6ACCD;">localhost</span><span style="color:#89DDFF;">-</span><span style="color:#A6ACCD;">slow.log</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;">SHOW </span><span style="color:#F78C6C;">GLOBAL</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">STATUS</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">LIKE</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%Slow_queries%</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><h3 id="_4-日志分析工具mysqldumpslow" tabindex="-1">4 日志分析工具mysqldumpslow <a class="header-anchor" href="#_4-日志分析工具mysqldumpslow" aria-label="Permalink to &quot;4 日志分析工具mysqldumpslow&quot;">​</a></h3><ol><li><p>在生产环境中，如果要手工分析日志，查找、分析SQL，显然是个体力活，MySQL提供了日志分析工具mysqldumpslow。</p></li><li><p>查看mysqldumpslow的帮助信息</p></li></ol><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">a)   mysqldumpslow --help</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">·    -a: 将数字抽象成N，字符串抽象成S</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">·    -s: 是表示按照何种方式排序；</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;"> c: 访问次数</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;"> l: 锁定时间</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;"> r: 返回记录</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;"> **t:** **查询时间**</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;"> al:平均锁定时间</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;"> ar:平均返回记录数</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;"> at:平均查询时间</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">·    -t: 即为返回前面多少条的数据；</span></span>
<span class="line"><span style="color:#A6ACCD;"></span></span>
<span class="line"><span style="color:#A6ACCD;">·    -g: 后边搭配一个正则匹配模式，大小写不敏感的；</span></span></code></pre></div><div class="language-sh"><button title="Copy Code" class="copy"></button><span class="lang">sh</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;"># 得到返回记录集最多的10个SQL  </span></span>
<span class="line"><span style="color:#FFCB6B;">mysqldumpslow</span><span style="color:#A6ACCD;">  </span><span style="color:#C3E88D;">-s</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">r</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-t</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/var/lib/mysql/localhost-slow.log</span><span style="color:#A6ACCD;">  </span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 得到访问次数最多的10个SQL  </span></span>
<span class="line"><span style="color:#FFCB6B;">mysqldumpslow</span><span style="color:#A6ACCD;">  </span><span style="color:#C3E88D;">-s</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">c</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-t</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/var/lib/mysql/localhost-slow.log</span><span style="color:#A6ACCD;">  </span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 得到按照时间排序的前10条里面含有左连接的查询语句  </span></span>
<span class="line"><span style="color:#FFCB6B;">mysqldumpslow</span><span style="color:#A6ACCD;">  </span><span style="color:#C3E88D;">-s</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">t</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-t</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-g</span><span style="color:#A6ACCD;">  </span><span style="color:#89DDFF;">&quot;</span><span style="color:#C3E88D;">left join</span><span style="color:#89DDFF;">&quot;</span><span style="color:#A6ACCD;">  </span><span style="color:#C3E88D;">/var/lib/mysql/localhost-slow.log</span><span style="color:#A6ACCD;">  </span></span>
<span class="line"><span style="color:#676E95;font-style:italic;"># 另外建议在使用这些命令时结合 | 和more 使用 ，否则有可能出现爆屏情况  </span></span>
<span class="line"><span style="color:#FFCB6B;">mysqldumpslow</span><span style="color:#A6ACCD;">  </span><span style="color:#C3E88D;">-s</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">r</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">-t</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;"> </span><span style="color:#C3E88D;">/var/lib/mysql/localhost-slow.log</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">|</span><span style="color:#A6ACCD;"> </span><span style="color:#FFCB6B;">more</span></span></code></pre></div><h2 id="索引分析和explain⭐" tabindex="-1">索引分析和EXPLAIN⭐ <a class="header-anchor" href="#索引分析和explain⭐" aria-label="Permalink to &quot;索引分析和EXPLAIN⭐&quot;">​</a></h2><blockquote><p>可以使用EXPLAIN，选择索引过程可以使用 optimizer_trace</p></blockquote><h3 id="_1-explain是什么" tabindex="-1">1 EXPLAIN是什么 <a class="header-anchor" href="#_1-explain是什么" aria-label="Permalink to &quot;1 EXPLAIN是什么&quot;">​</a></h3><blockquote><p>使用EXPLAIN关键字可以模拟优化器执行SQL查询语句，从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是表结构的性能瓶颈。</p></blockquote><h3 id="_2-explain的用法" tabindex="-1">2 EXPLAIN的用法 <a class="header-anchor" href="#_2-explain的用法" aria-label="Permalink to &quot;2 EXPLAIN的用法&quot;">​</a></h3><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#89DDFF;">+</span><span style="color:#A6ACCD;"> SQL语句</span></span></code></pre></div><p><strong>数据准备：</strong></p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301554100.png" alt="image-20221130155426994" style="zoom:80%;"><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">create</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">database</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">atguigudb</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#F78C6C;">USE</span><span style="color:#A6ACCD;"> atguigudb;</span></span>
<span class="line"><span style="color:#A6ACCD;"> </span></span>
<span class="line"><span style="color:#F78C6C;">CREATE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">TABLE</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">t1</span><span style="color:#A6ACCD;">(id </span><span style="color:#C792EA;">INT</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;">) AUTO_INCREMENT, content </span><span style="color:#C792EA;">VARCHAR</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">NULL</span><span style="color:#A6ACCD;">, </span><span style="color:#C792EA;">PRIMARY KEY</span><span style="color:#A6ACCD;"> (id));</span></span>
<span class="line"><span style="color:#F78C6C;">CREATE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">TABLE</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">t2</span><span style="color:#A6ACCD;">(id </span><span style="color:#C792EA;">INT</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;">) AUTO_INCREMENT, content </span><span style="color:#C792EA;">VARCHAR</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">NULL</span><span style="color:#A6ACCD;">, </span><span style="color:#C792EA;">PRIMARY KEY</span><span style="color:#A6ACCD;"> (id));</span></span>
<span class="line"><span style="color:#F78C6C;">CREATE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">TABLE</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">t3</span><span style="color:#A6ACCD;">(id </span><span style="color:#C792EA;">INT</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;">) AUTO_INCREMENT, content </span><span style="color:#C792EA;">VARCHAR</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">NULL</span><span style="color:#A6ACCD;">, </span><span style="color:#C792EA;">PRIMARY KEY</span><span style="color:#A6ACCD;"> (id));</span></span>
<span class="line"><span style="color:#F78C6C;">CREATE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">TABLE</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">t4</span><span style="color:#A6ACCD;">(id </span><span style="color:#C792EA;">INT</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">10</span><span style="color:#A6ACCD;">) AUTO_INCREMENT, content1 </span><span style="color:#C792EA;">VARCHAR</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">NULL</span><span style="color:#A6ACCD;">, content2 </span><span style="color:#C792EA;">VARCHAR</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">100</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">NULL</span><span style="color:#A6ACCD;">, </span><span style="color:#C792EA;">PRIMARY KEY</span><span style="color:#A6ACCD;"> (id));</span></span>
<span class="line"></span>
<span class="line"><span style="color:#F78C6C;">CREATE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">INDEX</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">idx_content1</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">ON</span><span style="color:#A6ACCD;"> t4(content1);  </span><span style="color:#676E95;font-style:italic;">-- 普通索引</span></span>
<span class="line"></span>
<span class="line"><span style="color:#A6ACCD;"># 以下新增sql多执行几次，以便演示</span></span>
<span class="line"><span style="color:#F78C6C;">INSERT INTO</span><span style="color:#A6ACCD;"> t1(content) </span><span style="color:#F78C6C;">VALUES</span><span style="color:#A6ACCD;">(</span><span style="color:#82AAFF;">CONCAT</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">t1_</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#82AAFF;">FLOOR</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">+</span><span style="color:#82AAFF;">RAND</span><span style="color:#A6ACCD;">()</span><span style="color:#89DDFF;">*</span><span style="color:#F78C6C;">1000</span><span style="color:#A6ACCD;">)));</span></span>
<span class="line"><span style="color:#F78C6C;">INSERT INTO</span><span style="color:#A6ACCD;"> t2(content) </span><span style="color:#F78C6C;">VALUES</span><span style="color:#A6ACCD;">(</span><span style="color:#82AAFF;">CONCAT</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">t2_</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#82AAFF;">FLOOR</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">+</span><span style="color:#82AAFF;">RAND</span><span style="color:#A6ACCD;">()</span><span style="color:#89DDFF;">*</span><span style="color:#F78C6C;">1000</span><span style="color:#A6ACCD;">)));</span></span>
<span class="line"><span style="color:#F78C6C;">INSERT INTO</span><span style="color:#A6ACCD;"> t3(content) </span><span style="color:#F78C6C;">VALUES</span><span style="color:#A6ACCD;">(</span><span style="color:#82AAFF;">CONCAT</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">t3_</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#82AAFF;">FLOOR</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">+</span><span style="color:#82AAFF;">RAND</span><span style="color:#A6ACCD;">()</span><span style="color:#89DDFF;">*</span><span style="color:#F78C6C;">1000</span><span style="color:#A6ACCD;">)));</span></span>
<span class="line"><span style="color:#F78C6C;">INSERT INTO</span><span style="color:#A6ACCD;"> t4(content1, content2) </span><span style="color:#F78C6C;">VALUES</span><span style="color:#A6ACCD;">(</span><span style="color:#82AAFF;">CONCAT</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">t4_</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#82AAFF;">FLOOR</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">+</span><span style="color:#82AAFF;">RAND</span><span style="color:#A6ACCD;">()</span><span style="color:#89DDFF;">*</span><span style="color:#F78C6C;">1000</span><span style="color:#A6ACCD;">)), </span><span style="color:#82AAFF;">CONCAT</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">t4_</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">,</span><span style="color:#82AAFF;">FLOOR</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1</span><span style="color:#89DDFF;">+</span><span style="color:#82AAFF;">RAND</span><span style="color:#A6ACCD;">()</span><span style="color:#89DDFF;">*</span><span style="color:#F78C6C;">1000</span><span style="color:#A6ACCD;">)));</span></span></code></pre></div><h3 id="_3-各字段解释" tabindex="-1">3 各字段解释 <a class="header-anchor" href="#_3-各字段解释" aria-label="Permalink to &quot;3 各字段解释&quot;">​</a></h3><h4 id="_1-table" tabindex="-1">1 table <a class="header-anchor" href="#_1-table" aria-label="Permalink to &quot;1 table&quot;">​</a></h4><p>**单表：**显示这一行的数据是关于哪张表的</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059961.png" alt="image-20220710101402666" style="zoom:80%;"><p>**多表关联：**t1为驱动表，t2为被驱动表。</p><p><code>注意：</code>内连接时，MySQL性能优化器会自动判断哪个表是驱动表，哪个表示被驱动表，和书写的顺序无关</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1 </span><span style="color:#F78C6C;">INNER JOIN</span><span style="color:#A6ACCD;"> t2;</span></span></code></pre></div><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059419.png" alt="image-20220711122444380"></p><h4 id="_2-id" tabindex="-1">2 id <a class="header-anchor" href="#_2-id" aria-label="Permalink to &quot;2 id&quot;">​</a></h4><p>表示查询中执行select子句或操作表的顺序</p><p>**id相同：**执行顺序由上至下</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1, t2, t3;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059457.png" alt="image-20220710000757241" style="zoom:80%;"><p>**id不同：**如果是子查询，id的序号会递增，id值越大优先级越高，越先被执行</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> t1.id </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> t1.id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">(</span></span>
<span class="line"><span style="color:#A6ACCD;">  </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> t2.id </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t2 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> t2.id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">(</span></span>
<span class="line"><span style="color:#A6ACCD;">    </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> t3.id </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t3 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> t3.content </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">t3_434</span><span style="color:#89DDFF;">&#39;</span></span>
<span class="line"><span style="color:#A6ACCD;">  )</span></span>
<span class="line"><span style="color:#A6ACCD;">);</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059477.png" alt="image-20220710000950098" style="zoom:80%;"><p><code>注意：</code>查询优化器可能对涉及子查询的语句进行优化，<code>转为连接查询</code></p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> content </span><span style="color:#F78C6C;">IN</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> content </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t2 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> content </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">a</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">);</span></span></code></pre></div><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059556.png" alt="image-20220711123408605"></p><p>**id为NULL：**最后执行</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1 </span><span style="color:#F78C6C;">UNION</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t2;</span></span></code></pre></div><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059797.png" alt="image-20220710001512891"></p><p><strong>小结：</strong></p><blockquote><ul><li>id如果相同，可以认为是一组，从上往下顺序执行</li><li>在所有组中，id值越大，优先级越高，越先执行</li><li>关注点：id号每个号码，表示一趟独立的查询, 一个sql的查询趟数越少越好</li></ul></blockquote><h4 id="_3-select-type" tabindex="-1">3 select_type <a class="header-anchor" href="#_3-select-type" aria-label="Permalink to &quot;3 select_type&quot;">​</a></h4><p>查询的类型，主要是用于区别普通查询、联合查询、子查询等的复杂查询。</p><p>**SIMPLE：**简单查询。查询中不包含子查询或者UNION。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059841.png" alt="image-20220710001930811" style="zoom:80%;"><p>**PRIMARY：**主查询。查询中若包含子查询，则最外层查询被标记为PRIMARY。</p><p>**SUBQUERY：**子查询。在SELECT或WHERE列表中包含了子查询。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t3 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> ( </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t2 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> content</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">a</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">);</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059951.png" alt="image-20220710002145309" style="zoom:80%;"><p>**DEPENDENT SUBQUREY：**如果包含了子查询，并且查询语句不能被优化器转换为连接查询，并且子查询是<code>相关子查询（子查询基于外部数据列）</code>，则子查询就是DEPENDENT SUBQUREY。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t3 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> ( </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t2 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> content </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> t3.content);</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059068.png" alt="image-20220710002444782" style="zoom:80%;"><p>**UNCACHEABLE SUBQUREY：**表示这个subquery的查询要受到外部系统变量的影响</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t3 </span></span>
<span class="line"><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> ( </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t2 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> content </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> @@character_set_server);</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059095.png" alt="image-20220710002604613" style="zoom:80%;"><p>**UNION：**对于包含UNION或者UNION ALL的查询语句，除了最左边的查询是PRIMARY，其余的查询都是UNION。</p><p>**UNION RESULT：**UNION会对查询结果进行查询去重，MYSQL会使用临时表来完成UNION查询的去重工作，针对这个临时表的查询就是&quot;UNION RESULT&quot;。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span></span>
<span class="line"><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t3 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> </span></span>
<span class="line"><span style="color:#F78C6C;">UNION</span><span style="color:#A6ACCD;">  </span></span>
<span class="line"><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t2 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059255.png" alt="image-20220710003049587" style="zoom:80%;"><p>**DEPENDENT UNION：**子查询中的UNION或者UNION ALL，除了最左边的查询是DEPENDENT SUBQUREY，其余的查询都是DEPENDENT UNION。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> content </span><span style="color:#F78C6C;">IN</span></span>
<span class="line"><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> content </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t2 </span><span style="color:#F78C6C;">UNION</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> content </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t3);</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059281.png" alt="image-20220710110732730" style="zoom:80%;"><p>**DERIVED：**在包含<code>派生表（子查询在from子句中）</code>的查询中，MySQL会递归执行这些子查询，把结果放在临时表里。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> ( </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> content, </span><span style="color:#82AAFF;">COUNT</span><span style="color:#A6ACCD;">(</span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">AS</span><span style="color:#A6ACCD;"> c </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1 </span><span style="color:#F78C6C;">GROUP BY</span><span style="color:#A6ACCD;"> content</span></span>
<span class="line"><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">AS</span><span style="color:#A6ACCD;"> derived_t1 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> c </span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p>这里的<code>&lt;derived2&gt;</code>就是在id为2的查询中产生的派生表。</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059503.png" alt="image-20220710153504037" style="zoom:80%;"><p>**补充：**MySQL在处理带有派生表的语句时，优先尝试把派生表和外层查询进行合并，如果不行，再把派生表<code>物化掉（执行子查询，并把结果放入临时表）</code>，然后执行查询。下面的例子就是就是将派生表和外层查询进行合并的例子：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> content </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">t1_832</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">) </span><span style="color:#F78C6C;">AS</span><span style="color:#A6ACCD;"> derived_t1;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059526.png" alt="image-20220710153921679" style="zoom:80%;"><p>**MATERIALIZED：**优化器对于包含子查询的语句，<code>如果选择将子查询物化后再与外层查询连接查询</code>，该子查询的类型就是MATERIALIZED。如下的例子中，查询优化器先将子查询转换成物化表，然后将t1和物化表进行连接查询。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> content </span><span style="color:#F78C6C;">IN</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> content </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t2);</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059624.png" alt="image-20220710155650935" style="zoom:80%;"><h4 id="_4-partitions" tabindex="-1">4 partitions <a class="header-anchor" href="#_4-partitions" aria-label="Permalink to &quot;4 partitions&quot;">​</a></h4><p>代表分区表中的命中情况，非分区表，该项为NULL</p><h4 id="_5-type-☆" tabindex="-1">5 type <strong>☆</strong> <a class="header-anchor" href="#_5-type-☆" aria-label="Permalink to &quot;5 type **☆**&quot;">​</a></h4><blockquote><p>**说明：**结果值从最好到最坏依次是：</p><p><code>system &gt; const &gt; eq_ref &gt; ref</code> &gt; fulltext &gt; ref_or_null &gt; index_merge &gt; unique_subquery &gt; index_subquery &gt; <code>range &gt; index &gt; ALL</code></p><p><code>比较重要的包含：system、const 、eq_ref 、ref、range &gt; index &gt; ALL</code></p><p>SQL 性能优化的目标：至少要达到 <code>range</code> 级别，要求是 <code>ref</code> 级别，最好是 <code>consts</code>级别。（阿里巴巴 开发手册要求）</p></blockquote><p>**ALL：**全表扫描。Full Table Scan，将遍历全表以找到匹配的行</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1;</span></span></code></pre></div><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059806.png" alt="image-20220712065946659"></p><p>**index：**当使用<code>覆盖索引</code>，但需要扫描全部的索引记录时</p><p><code>覆盖索引：</code>如果能通过读取索引就可以得到想要的数据，那就不需要读取用户记录，或者不用再做回表操作了。一个索引包含了满足查询结果的数据就叫做覆盖索引。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 只需要读取聚簇索引部分的非叶子节点，就可以得到id的值，不需要查询叶子节点</span></span>
<span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1;</span></span></code></pre></div><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059924.png" alt="image-20220712065815768"></p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 只需要读取二级索引，就可以在二级索引中获取到想要的数据，不需要再根据叶子节点中的id做回表操作</span></span>
<span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> id, deptId </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t_emp;</span></span></code></pre></div><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059013.png" alt="image-20220712065922882"></p><p>**range：**只检索给定范围的行，使用一个索引来选择行。key 列显示使用了哪个索引，一般就是在你的where语句中出现了between、&lt;、&gt;、in等的查询。这种范围扫描索引扫描比全表扫描要好，因为它只需要开始于索引的某一点，而结束于另一点，不用扫描全部索引。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">IN</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">, </span><span style="color:#F78C6C;">3</span><span style="color:#A6ACCD;">);</span></span></code></pre></div><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059092.png" alt="image-20220712070042666"></p><p>**ref：**通过普通二级索引列与常量进行等值匹配时</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t_emp </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> deptId </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059109.png" alt="image-20220712070727963"></p><p>**eq_ref：**连接查询时通过主键或不允许NULL值的唯一二级索引列进行等值匹配时</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1, t2 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> t1.id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> t2.id;</span></span></code></pre></div><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059193.png" alt="image-20220712070851089"></p><p>**const：**根据<code>主键</code>或者<code>唯一二级索引</code>列与<code>常数</code>进行匹配时</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059455.png" alt="image-20220712070944090"></p><p>**system：**MyISAM引擎中，当表中只有一条记录时。<code>（这是所有type的值中性能最高的场景）</code></p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#F78C6C;">CREATE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">TABLE</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">t</span><span style="color:#A6ACCD;">(i </span><span style="color:#C792EA;">int</span><span style="color:#A6ACCD;">) Engine</span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;">MyISAM;</span></span>
<span class="line"><span style="color:#F78C6C;">INSERT INTO</span><span style="color:#A6ACCD;"> t </span><span style="color:#F78C6C;">VALUES</span><span style="color:#A6ACCD;">(</span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t;</span></span></code></pre></div><p><strong>其他不太常见的类型（了解）：</strong></p><p><strong>index_subquery</strong>：利用<code>普通索引</code>来关联子查询，针对包含有IN子查询的查询语句。<code>content1是普通索引字段</code></p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> content </span><span style="color:#F78C6C;">IN</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> content1 </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t4 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> t1.content </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> t4.content2) </span><span style="color:#F78C6C;">OR</span><span style="color:#A6ACCD;"> content </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">a</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059494.png" alt="image-20220712071057817" style="zoom:80%;"><p><strong>unique_subquery</strong>：类似于index_subquery，利用<code>唯一索引</code>来关联子查询。<code>t2的id是主键，也可以理解为唯一的索引字段</code></p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">IN</span><span style="color:#A6ACCD;"> (</span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t2 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> t1.content </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> t2.content) </span><span style="color:#F78C6C;">OR</span><span style="color:#A6ACCD;"> content </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">a</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059677.png" alt="image-20220712071138320"></p><p><strong>index_merge</strong>：在查询过程中需要<code>多个索引组合使用</code>，通常出现在有 or 的关键字的sql中。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t_emp </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> deptId </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">OR</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059769.png" alt="image-20220711132125501"></p><p><strong>ref_or_null</strong>：当对普通二级索引进行等值匹配，且该索引列的值也可以是NULL值时。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t_emp </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> deptId </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">OR</span><span style="color:#A6ACCD;"> deptId </span><span style="color:#F78C6C;">IS</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">NULL</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059796.png" alt="image-20220711131831315"></p><p>**fulltext：**全文索引。<code>一般通过搜索引擎实现，这里我们不展开。</code></p><h4 id="_6-possible-keys-和-keys-☆" tabindex="-1">6 possible_keys 和 keys ☆ <a class="header-anchor" href="#_6-possible-keys-和-keys-☆" aria-label="Permalink to &quot;6 possible_keys 和 keys ☆&quot;">​</a></h4><blockquote><ul><li><p><code>possible_keys</code>表示执行查询时可能用到的索引，一个或多个。 查询涉及到的字段上若存在索引，则该索引将被列出，<strong>但不一定被查询实际使用</strong>。</p></li><li><p><code>keys</code>表示实际使用的索引。如果为NULL，则没有使用索引。</p></li></ul></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059021.png" alt="image-20220710142152514"></p><h4 id="_7-key-len-☆" tabindex="-1">7 key_len <strong>☆</strong> <a class="header-anchor" href="#_7-key-len-☆" aria-label="Permalink to &quot;7 key_len **☆**&quot;">​</a></h4><blockquote><p>表示索引使用的字节数，根据这个值可以判断索引的使用情况，<code>检查是否充分利用了索引，针对联合索引值越大越好。</code></p></blockquote><p><strong>如何计算：</strong></p><blockquote><ol><li>先看索引上字段的类型+长度。比如：int=4 ; varchar(20) =20 ; char(20) =20</li><li>如果是varchar或者char这种字符串字段，视字符集要乘不同的值，比如utf8要乘 3，如果是utf8mb4要乘4，GBK要乘2</li><li>varchar这种动态字符串要加2个字节</li><li>允许为空的字段要加1个字节</li></ol></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 创建索引</span></span>
<span class="line"><span style="color:#F78C6C;">CREATE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">INDEX</span><span style="color:#A6ACCD;"> </span><span style="color:#82AAFF;">idx_age_name</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">ON</span><span style="color:#A6ACCD;"> t_emp(age, </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;">);</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 测试1</span></span>
<span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t_emp </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> age </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">30</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">AND</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">ab%</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 测试2</span></span>
<span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t_emp </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> age </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">30</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059064.png" alt="image-20220710130548971" style="zoom:80%;"><h4 id="_8-ref" tabindex="-1">8 ref <a class="header-anchor" href="#_8-ref" aria-label="Permalink to &quot;8 ref&quot;">​</a></h4><p>显示与key中的索引进行比较的列或常量。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- ref=atguigudb.t1.id   关联查询时出现，t2表和t1表的哪一列进行关联</span></span>
<span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1, t2 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> t1.id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> t2.id;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- ref=const  与索引列进行等值比较的东西是啥，const表示一个常数</span></span>
<span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t_emp </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> age </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">30</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059086.png" alt="image-20220709211819944" style="zoom:80%;"><h4 id="_9-rows-☆" tabindex="-1">9 rows ☆ <a class="header-anchor" href="#_9-rows-☆" aria-label="Permalink to &quot;9 rows ☆&quot;">​</a></h4><p>MySQL认为它执行查询时必须检查的行数。值越小越好。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 如果是全表扫描，rows的值就是表中数据的估计行数</span></span>
<span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t_emp </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> empno </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">10001</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 如果是使用索引查询，rows的值就是预计扫描索引记录行数</span></span>
<span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t_emp </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> deptId </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059264.png" alt="image-20220710131916240" style="zoom:80%;"><h4 id="_10-filtered" tabindex="-1">10 filtered <a class="header-anchor" href="#_10-filtered" aria-label="Permalink to &quot;10 filtered&quot;">​</a></h4><p>最后查询出来的数据占所有服务器端检查行数（rows）的<code>百分比</code>。值越大越好。</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- 先根据二级索引deptId找到数据的主键，有3条记录满足条件，</span></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 再根据主键进行回表，最终找到3条记录，有100%的记录满足条件</span></span>
<span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t_emp </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> deptId </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span>
<span class="line"></span>
<span class="line"><span style="color:#676E95;font-style:italic;">-- 这个例子如果name列是索引列则 filtered = 100 否则filtered = 10(全表扫描)</span></span>
<span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t_emp </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">风清扬</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059350.png" alt="image-20220709212722601" style="zoom:80%;"><h4 id="_11-extra-☆" tabindex="-1">11 Extra ☆ <a class="header-anchor" href="#_11-extra-☆" aria-label="Permalink to &quot;11 Extra ☆&quot;">​</a></h4><p>包含不适合在其他列中显示但十分重要的额外信息。通过这些额外信息来<code>理解MySQL到底将如何执行当前的查询语句</code>。MySQL提供的额外信息有好几十个，这里只挑介绍比较重要的介绍。</p><p><strong>Impossible WHERE</strong>：where子句的值总是false</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t_emp </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">!=</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">1</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059365.png" alt="image-20220709231638201" style="zoom:80%;"><ul><li>**Using where：**使用了where，但在where上有字段没有创建索引</li></ul><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t_emp </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">`</span><span style="color:#C3E88D;">name</span><span style="color:#89DDFF;">`</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">风清扬</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059617.png" alt="image-20220709215122017" style="zoom:80%;"><p>**Using temporary：**使了用临时表保存中间结果</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT DISTINCT</span><span style="color:#A6ACCD;"> content </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059634.png" alt="image-20220710181100102" style="zoom:80%;"><p><strong>Using filesort：</strong></p><p>在对查询结果中的记录进行排序时，是可以使用索引的，如下所示：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1 </span><span style="color:#F78C6C;">ORDER BY</span><span style="color:#A6ACCD;"> id;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059652.png" alt="image-20220710172607190" style="zoom:80%;"><p>如果排序操作无法使用到索引，只能在内存中（记录较少时）或者磁盘中（记录较多时）进行排序（filesort），如下所示：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1 </span><span style="color:#F78C6C;">ORDER BY</span><span style="color:#A6ACCD;"> content;</span></span></code></pre></div><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059910.png" alt="image-20220710172926396"></p><ul><li>**Using index：**使用了覆盖索引，表示直接访问索引就足够获取到所需要的数据，不需要通过索引回表</li></ul><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> id, content1 </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t4;</span></span></code></pre></div><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059939.png" alt="image-20220712071716131"></p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1;</span></span></code></pre></div><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059956.png" alt="image-20220712072055566"></p><p>**Using index condition：**叫作 <code>Index Condition Pushdown Optimization （索引下推优化）</code></p><ul><li><code>如果没有索引下推（ICP）</code>，那么MySQL在存储引擎层找到满足<code>content1 &gt; &#39;z&#39;</code>条件的第一条二级索引记录。<code>主键值进行回表</code>，返回完整的记录给server层，server层再判断其他的搜索条件是否成立。如果成立则保留该记录，否则跳过该记录，然后向存储引擎层要下一条记录。</li><li><code>如果使用了索引下推（ICP</code>），那么MySQL在存储引擎层找到满足<code>content1 &gt; &#39;z&#39;</code>条件的第一条二级索引记录。<code>不着急执行回表</code>，而是在这条记录上先判断一下所有关于<code>idx_content1</code>索引中包含的条件是否成立，也就是<code>content1 &gt; &#39;z&#39; AND content1 LIKE &#39;%a&#39;</code>是否成立。如果这些条件不成立，则直接跳过该二级索引记录，去找下一条二级索引记录；如果这些条件成立，则执行回表操作，返回完整的记录给server层。</li></ul><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#676E95;font-style:italic;">-- content1列上有索引idx_content1</span></span>
<span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t4 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> content1 </span><span style="color:#89DDFF;">&gt;</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">z</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">AND</span><span style="color:#A6ACCD;"> content1 </span><span style="color:#F78C6C;">LIKE</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">&#39;</span><span style="color:#C3E88D;">%a</span><span style="color:#89DDFF;">&#39;</span><span style="color:#A6ACCD;">;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059208.png" alt="image-20220710180257692" style="zoom:80%;"><p>**注意：**如果这里的查询条件<code>只有content1 &gt; &#39;z&#39;</code>，那么找到满足条件的索引后也会进行一次索引下推的操作，判断content1 &gt; &#39;z&#39;是否成立（这是源码中为了编程方便做的冗余判断）</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059226.png" alt="image-20220712012108900" style="zoom:80%;"><p>**Using join buffer：**在连接查询时，当被驱动表不能有效的利用索引时，MySQL会为其分配一块名为连接缓冲区（join buffer）的内存来加快查询速度</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN  </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t1, t2 </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> t1.content </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> t2.content;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059243.png" alt="image-20220710182356817" style="zoom:80%;"><p>下面这个例子就是被驱动表使用了索引：</p><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">EXPLAIN </span><span style="color:#F78C6C;">SELECT</span><span style="color:#A6ACCD;"> </span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">FROM</span><span style="color:#A6ACCD;"> t_emp, t_dept </span><span style="color:#F78C6C;">WHERE</span><span style="color:#A6ACCD;"> t_dept.id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> t_emp.deptId;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059391.png" alt="image-20220710182524371" style="zoom:80%;"><h2 id="mysql数据库cpu飙升如何分析" tabindex="-1">MySQL数据库cpu飙升如何分析 <a class="header-anchor" href="#mysql数据库cpu飙升如何分析" aria-label="Permalink to &quot;MySQL数据库cpu飙升如何分析&quot;">​</a></h2><p>重点是定位问题。</p><h3 id="_1-使用top观察mysqld的cpu利用率" tabindex="-1">1 使用top观察mysqld的cpu利用率 <a class="header-anchor" href="#_1-使用top观察mysqld的cpu利用率" aria-label="Permalink to &quot;1 使用top观察mysqld的cpu利用率&quot;">​</a></h3><blockquote><ol><li><p>切换到常用的数据库</p></li><li><p>使用show full processlist;查看会话</p></li><li><p>观察是哪些sql消耗了资源，其中重点观察state指标</p></li><li><p>定位到具体SQL</p></li></ol></blockquote><h3 id="_2-pidstat" tabindex="-1"><strong>2 pidstat</strong> <a class="header-anchor" href="#_2-pidstat" aria-label="Permalink to &quot;**2 pidstat**&quot;">​</a></h3><blockquote><ol><li>定位到线程</li><li>在PERFORMANCE_SCHEMA.THREADS中记录了thread_os_id 找到线程执行的sql</li><li>根据操作系统id可以到processlist表找到对应的会话</li><li>在会话中即可定位到问题sql</li></ol></blockquote><h3 id="_3-使用show-profile观察sql各个阶段耗时" tabindex="-1">3 使用show profile观察SQL各个阶段耗时 <a class="header-anchor" href="#_3-使用show-profile观察sql各个阶段耗时" aria-label="Permalink to &quot;3 使用show profile观察SQL各个阶段耗时&quot;">​</a></h3><h3 id="_4-服务器上是否运行了其他程序" tabindex="-1">4 服务器上是否运行了其他程序 <a class="header-anchor" href="#_4-服务器上是否运行了其他程序" aria-label="Permalink to &quot;4 服务器上是否运行了其他程序&quot;">​</a></h3><h3 id="_5-检查一下是否有慢查询" tabindex="-1">5 检查一下是否有慢查询 <a class="header-anchor" href="#_5-检查一下是否有慢查询" aria-label="Permalink to &quot;5 检查一下是否有慢查询&quot;">​</a></h3><h3 id="_6-pref-top" tabindex="-1">6 pref top <a class="header-anchor" href="#_6-pref-top" aria-label="Permalink to &quot;6 pref top&quot;">​</a></h3><p>使用pref 工具分析哪些函数引发的cpu过高来追踪定位</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059495.png" alt="image-20221106160437906" style="zoom:80%;"><h2 id="有没有进行过分库分表" tabindex="-1">有没有进行过分库分表？ <a class="header-anchor" href="#有没有进行过分库分表" aria-label="Permalink to &quot;有没有进行过分库分表？&quot;">​</a></h2><h3 id="_1-什么是分库分表" tabindex="-1">1 什么是分库分表？ <a class="header-anchor" href="#_1-什么是分库分表" aria-label="Permalink to &quot;1 什么是分库分表？&quot;">​</a></h3><h4 id="_1-垂直分库" tabindex="-1">1 垂直分库 <a class="header-anchor" href="#_1-垂直分库" aria-label="Permalink to &quot;1 垂直分库&quot;">​</a></h4><p>一个数据库由很多表的构成，每个表对应着<strong>不同的业务</strong>，垂直切分是指按照业务将表进行分类，分布到不同 的数据库上面，这样也就将数据或者说压力分担到不同的库上面，如下图：</p><p>​ <img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059591.jpg" style="zoom:80%;"></p><p>系统被切分成了，用户，订单交易，支付几个模块。</p><h4 id="_2-水平分表" tabindex="-1">2 水平分表 <a class="header-anchor" href="#_2-水平分表" aria-label="Permalink to &quot;2 水平分表&quot;">​</a></h4><p>把一张表里的内容按照不同的规则 写到不同的库里</p><p>相对于垂直拆分，水平拆分不是将表做分类，而是按照某个字段的某种规则来分散到多个库之中，每个表中包含一部分数据。简单来说，我们可以将数据的水平切分理解为是按照数据行的切分，就是将表中的某些行切分 到一个数据库，而另外的某些行又切分到其他的数据库中，如图：</p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059610.jpg" style="zoom:67%;"><h3 id="_2-什么时候进行分库分表" tabindex="-1">2 什么时候进行分库分表 <a class="header-anchor" href="#_2-什么时候进行分库分表" aria-label="Permalink to &quot;2 什么时候进行分库分表&quot;">​</a></h3><blockquote><ol><li>能不分就不分</li><li>单机性能下降明显的时候</li><li>增加缓存（通常查询量比较大），细分业务</li><li>首先尝试主被集群，读写分离</li><li>尝试分库</li><li>尝试分表 -&gt; 冷热数据分离</li></ol></blockquote><p>大数据量下可以配合es完成高效查询</p><h3 id="_3-说一下实现分库分表工具的实现思路" tabindex="-1">3 说一下实现分库分表工具的实现思路 <a class="header-anchor" href="#_3-说一下实现分库分表工具的实现思路" aria-label="Permalink to &quot;3 说一下实现分库分表工具的实现思路&quot;">​</a></h3><blockquote><ol><li>伪装成mysql服务器，代理用户请求转发到真实服务器</li><li>基于本地aop实现，拦截sql，改写，路由和结果归集处理。</li></ol></blockquote><h3 id="_4-用过哪些分库分表工具" tabindex="-1">4 用过哪些分库分表工具？ <a class="header-anchor" href="#_4-用过哪些分库分表工具" aria-label="Permalink to &quot;4 用过哪些分库分表工具？&quot;">​</a></h3><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059907.png" alt="img" style="zoom:80%;"><h3 id="_5-分库分表后可能会有哪些问题" tabindex="-1">5 分库分表后可能会有哪些问题？ <a class="header-anchor" href="#_5-分库分表后可能会有哪些问题" aria-label="Permalink to &quot;5 分库分表后可能会有哪些问题？&quot;">​</a></h3><p>经典的问题</p><blockquote><ol><li>执行效率明显降低</li><li>表结构很难再次调整</li><li>引发分布式id问题</li><li>产生跨库join</li><li>代理类中间件网络io成为瓶颈</li></ol></blockquote><h2 id="说一下读写分离常见方案" tabindex="-1">说一下读写分离常见方案？ <a class="header-anchor" href="#说一下读写分离常见方案" aria-label="Permalink to &quot;说一下读写分离常见方案？&quot;">​</a></h2><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059014.png" alt="image-20221106171251532"></p><p><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301059038.png" alt="image-20221106171945037"></p><h2 id="视图和存储过程" tabindex="-1">视图和存储过程 <a class="header-anchor" href="#视图和存储过程" aria-label="Permalink to &quot;视图和存储过程&quot;">​</a></h2><h3 id="_1-视图" tabindex="-1">1 视图 <a class="header-anchor" href="#_1-视图" aria-label="Permalink to &quot;1 视图&quot;">​</a></h3><p>视图定义：</p><blockquote><p>1、视图是一个虚表，是从一个或几个基本表（或视图）导出的表。 2、只存放视图的定义，不存放视图对应的数据。 3、基表中的数据发生变化，从视图中查询出的数据也随之改变。</p></blockquote><p>视图的作用：</p><blockquote><p>1、视图能够简化用户的操作 2、视图使用户能以多种角度看待同一数据 3、视图对重构数据库提供了一定程度的逻辑独立性 4、视图能够对机密数据提供安全保护 5、适当的利用视图可以更清晰的表达查询</p></blockquote><h3 id="_2-什么是存储过程-有没有使用过" tabindex="-1">2 什么是存储过程？有没有使用过？ <a class="header-anchor" href="#_2-什么是存储过程-有没有使用过" aria-label="Permalink to &quot;2 什么是存储过程？有没有使用过？&quot;">​</a></h3><blockquote><p>项目中禁止使用存储过程，存储过程难以调试和扩展，更没有移植性</p></blockquote><h2 id="外键使用注意事项" tabindex="-1">外键使用注意事项 <a class="header-anchor" href="#外键使用注意事项" aria-label="Permalink to &quot;外键使用注意事项&quot;">​</a></h2><blockquote><p><strong>不得使用外键与级联，一切外键概念必须在应用层解决。</strong></p></blockquote><blockquote><p>说明：以学生和成绩的关系为例，学生表中的 student_id是主键，那么成绩表中的 student_id 则为外键。如果更新学生表中的 student_id，同时触发成绩表中的 student_id 更新，即为 级联更新。</p><p>外键与级联更新适用于单机低并发，不适合分布式、高并发集群；级联更新是强阻塞，存在数据库更新风暴的风险；外键影响数据库的插入速度。</p></blockquote><h2 id="用过processlist吗" tabindex="-1">用过processlist吗？ <a class="header-anchor" href="#用过processlist吗" aria-label="Permalink to &quot;用过processlist吗？&quot;">​</a></h2><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">show processlist ;</span></span></code></pre></div><img src="https://edu-8673.oss-cn-beijing.aliyuncs.com/img2022.12.30/202211301521535.png" alt="image-20221130152136416" style="zoom:80%;"><p>关键的就是state列，mysql列出的状态主要有以下几种：</p><ul><li>Checking table：正在检查数据表（这是自动的）。</li><li>Closing tables 正在将表中修改的数据刷新到磁盘中，同时正在关闭已经用完的表。这是一个很快的操作，如果不是这样的话，就应该确认磁盘空间是否已经满了或者磁盘是否正处于重负中。</li><li>Connect Out 复制从服务器正在连接主服务器。</li><li>Copying to tmp table on disk 由于临时结果集大于tmp_table_size，正在将临时表从内存存储转为磁盘存储以此节省内存。</li><li>Creating tmp table 正在创建临时表以存放部分查询结果。</li><li>deleting from main table 服务器正在执行多表删除中的第一部分，刚删除第一个表。</li><li>deleting from reference tables 服务器正在执行多表删除中的第二部分，正在删除其他表的记录。</li><li>Flushing tables 正在执行FLUSH TABLES，等待其他线程关闭数据表。</li><li>Killed 发送了一个kill请求给某线程，那么这个线程将会检查kill标志位，同时会放弃下一个kill请求。MySQL会在每次的主循环中检查kill标志位，不过有些情况下该线程可能会过一小段才能死掉。如果该线程程被其他线程锁住了，那么kill请求会在锁释放时马上生效。</li><li>Locked 被其他查询锁住了。</li><li>Sending data 正在处理Select查询的记录，同时正在把结果发送给客户端。Sending data”状态的含义，原来这个状态的名称很具有误导性，所谓的“Sending data”并不是单纯的发送数据，而是包括“收集 + 发送 数据”。</li><li>Sorting for group 正在为GROUP BY做排序。</li><li>Sorting for order 正在为ORDER BY做排序。</li><li>Opening tables 这个过程应该会很快，除非受到其他因素的干扰。例如，在执Alter TABLE或LOCK TABLE语句行完以前，数据表无法被其他线程打开。正尝试打开一个表。</li><li>Removing duplicates 正在执行一个Select DISTINCT方式的查询，但是MySQL无法在前一个阶段优化掉那些重复的记录。因此，MySQL需要再次去掉重复的记录，然后再把结果发送给客户端。</li><li>Reopen table 获得了对一个表的锁，但是必须在表结构修改之后才能获得这个锁。已经释放锁，关闭数据表，正尝试重新打开数据表。</li><li>Repair by sorting 修复指令正在排序以创建索引。</li><li>Repair with keycache 修复指令正在利用索引缓存一个一个地创建新索引。它会比Repair by sorting慢些。</li><li>Searching rows for update 正在讲符合条件的记录找出来以备更新。它必须在Update要修改相关的记录之前就完成了。</li><li>Sleeping 正在等待客户端发送新请求.</li><li>System lock 正在等待取得一个外部的系统锁。如果当前没有运行多个mysqld服务器同时请求同一个表，那么可以通过增加--skip-external-locking参数来禁止外部系统锁。</li><li>Upgrading lock Insert DELAYED正在尝试取得一个锁表以插入新记录。=</li><li>Updating 正在搜索匹配的记录，并且修改它们。</li><li>User Lock 正在等待GET_LOCK()。</li><li>Waiting for tables 该线程得到通知，数据表结构已经被修改了，需要重新打开数据表以取得新的结构。然后，为了能的重新打开数据表，必须等到所有其他线程关闭这个表。以下几种情况下会产生这个通知：FLUSH TABLES tbl_name, Alter TABLE, RENAME TABLE, REPAIR TABLE, ANALYZE TABLE,或OPTIMIZE TABLE。</li><li>waiting for handler insert Insert DELAYED已经处理完了所有待处理的插入操作，正在等待新的请求。</li></ul><h2 id="表有数千万数据如何优化查询⭐" tabindex="-1">表有数千万数据如何优化查询⭐ <a class="header-anchor" href="#表有数千万数据如何优化查询⭐" aria-label="Permalink to &quot;表有数千万数据如何优化查询⭐&quot;">​</a></h2><h3 id="_1-前端优化-减少查询" tabindex="-1">1 前端优化 减少查询 <a class="header-anchor" href="#_1-前端优化-减少查询" aria-label="Permalink to &quot;1 前端优化 减少查询&quot;">​</a></h3><blockquote><ol><li>合并请求:多个请求需要的数据尽量一条sql拿出来</li><li>会话保存：和用户会话相关的数据尽量一次取出重复使用</li><li>避免无效刷新</li></ol></blockquote><h3 id="_2-多级缓存-不要触及到数据库" tabindex="-1">2 多级缓存 不要触及到数据库 <a class="header-anchor" href="#_2-多级缓存-不要触及到数据库" aria-label="Permalink to &quot;2 多级缓存 不要触及到数据库&quot;">​</a></h3><blockquote><ol><li>应用层热点数据高速查询缓存（低一致性缓存）</li><li>高频查询大数据量镜像缓存（双写高一致性缓存）</li><li>入口层缓存（几乎不变的系统常量）</li></ol></blockquote><h3 id="_3-一定要高效使用索引" tabindex="-1">3 一定要高效使用索引 <a class="header-anchor" href="#_3-一定要高效使用索引" aria-label="Permalink to &quot;3 一定要高效使用索引&quot;">​</a></h3><blockquote><ol><li>使用explain 深入观察索引使用情况</li><li>检查select 字段最好满足索引覆盖</li><li>复合索引注意观察key_len索引使用情况</li><li>有分组，排序，注意file sort，合理配置相应的buffer大小</li></ol></blockquote><h3 id="_4-多种优化方式" tabindex="-1">4 多种优化方式 <a class="header-anchor" href="#_4-多种优化方式" aria-label="Permalink to &quot;4 多种优化方式&quot;">​</a></h3><blockquote><ol><li>检查查询是否可以分段查询，避免一次拿出过多无效数据</li><li><strong>多表关联查询是否可以设置冗余字段，是否可以简化多表查询或分批查询</strong></li><li>分而治之：<strong>把服务拆分成更小力度的微服务</strong></li><li><strong>冷热数据分库存储</strong></li><li><strong>读写分离，主被集群 然后再考虑分库分表</strong></li><li>使用合适的字段类型，比如varchar换成char</li></ol></blockquote><h2 id="count-列名-和-count-有什么区别" tabindex="-1">count(列名)和 count(*)有什么区别 <a class="header-anchor" href="#count-列名-和-count-有什么区别" aria-label="Permalink to &quot;count(列名)和 count(*)有什么区别&quot;">​</a></h2><blockquote><ul><li>count(*)是 SQL92 定义的</li><li>标准统计行数的语法，跟数据库无关，跟 NULL 和非 NULL 无关。</li><li>说明：<strong>count(*)会统计值为 NULL 的行，而 count(列名)不会统计此列为 NULL 值的行</strong></li></ul></blockquote><h2 id="如果有超大分页怎么处理" tabindex="-1">如果有超大分页怎么处理？ <a class="header-anchor" href="#如果有超大分页怎么处理" aria-label="Permalink to &quot;如果有超大分页怎么处理？&quot;">​</a></h2><blockquote><p>select name from user limit 10000,10;</p><p><strong>在使用的时候并不是跳过 offset 行，而是取 offset+N 行，然后返回放弃前 offset 行，返回 N 行</strong></p></blockquote><blockquote><p>通过索引优化的方案：如果<strong>主键自增</strong>可以 select name from user where id &gt; 10000 limit 10;</p></blockquote><blockquote><p>延迟关联：需要order by时，<strong>一定注意增加筛选条件，避免全表排序</strong></p></blockquote><blockquote><ul><li><p>where -&gt; order by -&gt; limit</p></li><li><p>减少select字段</p></li><li><p>优化相关参数避免filesort</p></li><li><p>一般大分页情况比较少（很少有人跳转到几百万页去查看数据），实际互联网业务中多数还是按顺序翻页，可以使用缓存提升前几页的查询效率，实际上大多数知名互联网项目也都是这么做的</p></li></ul></blockquote><p>在阿里巴巴《Java开发手册》中的建议：</p><blockquote><p>【推荐】利用延迟关联或者子查询优化超多分页场景。 说明：MySQL 并不是跳过 offset 行，而是取 offset+N 行，然后返回放弃前 offset 行，返回 N 行，那当 offset 特别大的时候，效率就非常的低下，要么控制返回的总页数，要么对超过 特定阈值的页数进行 SQL 改写。</p></blockquote><div class="language-sql"><button title="Copy Code" class="copy"></button><span class="lang">sql</span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;"># 正例：先快速定位需要获取的 id 段，然后再关联：</span></span>
<span class="line"><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> a.</span><span style="color:#89DDFF;">*</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> person a, (</span><span style="color:#F78C6C;">select</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">from</span><span style="color:#A6ACCD;"> person </span><span style="color:#F78C6C;">order by</span><span style="color:#A6ACCD;"> id </span><span style="color:#F78C6C;">limit</span><span style="color:#A6ACCD;"> </span><span style="color:#F78C6C;">0</span><span style="color:#A6ACCD;">,</span><span style="color:#F78C6C;">2</span><span style="color:#A6ACCD;">) b</span></span>
<span class="line"><span style="color:#F78C6C;">where</span><span style="color:#A6ACCD;"> a.id </span><span style="color:#89DDFF;">=</span><span style="color:#A6ACCD;"> b.id;</span></span></code></pre></div><h2 id="mysql毫无规律异常重启排查问题" tabindex="-1">MySQL毫无规律异常重启排查问题 <a class="header-anchor" href="#mysql毫无规律异常重启排查问题" aria-label="Permalink to &quot;MySQL毫无规律异常重启排查问题&quot;">​</a></h2><blockquote><p>首先是查看mysql和系统日志来定位错误</p></blockquote><p><strong>最常见的是关闭swap分区后OOM问题：</strong></p><blockquote><p>mysql 分为应用进程和守护进程。当应用进程内存占用过高的时候操作系统可能会kill掉进程，此时守护进程又帮我们重启了应用进程，运行一段时间后又出现OOM如此反复</p></blockquote><p>可以排查以下几个关键点</p><blockquote><ul><li>运行时内存占用率</li><li>mysql buffer相关参数</li><li>mysql 网络连接相关参数</li></ul></blockquote><p><strong>异常关机或kill -9 mysql 后导致表文件损坏</strong></p><blockquote><ul><li>直接使用备份</li><li>配置 innodb_force_recovery 跳过启动恢复过程</li></ul></blockquote><h2 id="mysql-线上修改表结构有哪些风险" tabindex="-1">MySQL 线上修改表结构有哪些风险? <a class="header-anchor" href="#mysql-线上修改表结构有哪些风险" aria-label="Permalink to &quot;MySQL 线上修改表结构有哪些风险?&quot;">​</a></h2><p>针对ddl命令，有以下几种方式</p><blockquote><ul><li>copy table 锁原表，创建临时表并拷贝数据。可能会锁表，导致无法读写</li><li>inplace 针对索引修改删除的优化，不需要拷贝所有数据。</li><li>Online DDL 细分DDL命令来决定是否锁表</li></ul></blockquote><blockquote><ul><li>ORM中的映射失效</li><li>索引失效</li></ul></blockquote><blockquote><p>建议：建个新表，导入数据后重命名</p></blockquote><h2 id="什么是mysql多实例部署" tabindex="-1">什么是MySQL多实例部署？ <a class="header-anchor" href="#什么是mysql多实例部署" aria-label="Permalink to &quot;什么是MySQL多实例部署？&quot;">​</a></h2><blockquote><p>指的是在一台主机上部署多个MySQL实例</p><p>主要目的是压榨服务器性能</p><p>缺点是互相影响，CPU跑满就会互相影响，导致全部都不能正常运行</p></blockquote><h1 id="索引常见知识点" tabindex="-1">索引常见知识点 <a class="header-anchor" href="#索引常见知识点" aria-label="Permalink to &quot;索引常见知识点&quot;">​</a></h1><p>今天来盘点一下关于MySQL索引常见的知识点本来这篇文章我前两个星期就打算写了，提纲都列好了，但是后面我去追《漫长的季节》这部剧去了，这就花了一个周末的时间，再加上后面一些其它的事，导致没来得及写不过不要紧，好饭不怕晚，虽迟但到，走起，开干！</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTssUJRoXV8HRbXyicfmOz8eiaubEunoglxpicGl4zvcwXV5OWibib4vDB6xaA/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>对了，本文主要是针对InnoDB存储引擎进行讲解。</p><h2 id="索引分类" tabindex="-1">索引分类 <a class="header-anchor" href="#索引分类" aria-label="Permalink to &quot;索引分类&quot;">​</a></h2><p>索引的分类可以从不同的维度进行分类</p><h3 id="_1、按使用的数据结构划分" tabindex="-1">1、按使用的数据结构划分 <a class="header-anchor" href="#_1、按使用的数据结构划分" aria-label="Permalink to &quot;1、按使用的数据结构划分&quot;">​</a></h3><ul><li>B+树索引</li><li>Hash索引</li><li>...</li></ul><h3 id="_2、按实际的物理存储数据构划分" tabindex="-1">2、按实际的物理存储数据构划分 <a class="header-anchor" href="#_2、按实际的物理存储数据构划分" aria-label="Permalink to &quot;2、按实际的物理存储数据构划分&quot;">​</a></h3><ul><li>聚簇索引</li><li>非聚簇索引（二级索引）</li></ul><p>聚簇索引和非聚簇索引后面会着重说。</p><h3 id="_3、按索引特性划分" tabindex="-1">3、按索引特性划分 <a class="header-anchor" href="#_3、按索引特性划分" aria-label="Permalink to &quot;3、按索引特性划分&quot;">​</a></h3><ul><li>主键索引</li><li>唯一索引</li><li>普通索引</li><li>全文索引</li><li>...</li></ul><h3 id="_4、按字段个数划分" tabindex="-1">4、按字段个数划分 <a class="header-anchor" href="#_4、按字段个数划分" aria-label="Permalink to &quot;4、按字段个数划分&quot;">​</a></h3><ul><li>单列索引</li><li>联合索引</li></ul><h2 id="索引数据结构" tabindex="-1">索引数据结构 <a class="header-anchor" href="#索引数据结构" aria-label="Permalink to &quot;索引数据结构&quot;">​</a></h2><h3 id="准备" tabindex="-1">准备 <a class="header-anchor" href="#准备" aria-label="Permalink to &quot;准备&quot;">​</a></h3><p>为了接下来文章更好地讲解，这里我准备了一张<code>user</code>表，接下来整篇文章的示例会以这张表来讲解</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">CREATE TABLE `user` (</span></span>
<span class="line"><span style="color:#A6ACCD;">  `id` int(10) NOT NULL AUTO_INCREMENT,</span></span>
<span class="line"><span style="color:#A6ACCD;">  `name` varchar(255) DEFAULT NULL,</span></span>
<span class="line"><span style="color:#A6ACCD;">  `age` int(10) DEFAULT NULL,</span></span>
<span class="line"><span style="color:#A6ACCD;">  `city` varchar(255) DEFAULT NULL,</span></span>
<span class="line"><span style="color:#A6ACCD;">  PRIMARY KEY (`id`)</span></span>
<span class="line"><span style="color:#A6ACCD;">) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;</span></span></code></pre></div><h3 id="hash索引" tabindex="-1">Hash索引 <a class="header-anchor" href="#hash索引" aria-label="Permalink to &quot;Hash索引&quot;">​</a></h3><blockquote><p>Hash索引其实用的不多，最主要是因为最常见的存储引擎InnoDB不支持显示地创建Hash索引，只支持自适应Hash索引。虽然可以使用sql语句在InnoDB显示声明Hash索引，但是其实是不生效的</p></blockquote><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTs5LCZp3IV8XlAtzS5MgrWW5qo1DFPwCmdZ7Fje6lEMV3E0p97noHKUg/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><blockquote><p>对name字段建立Hash索引，但是通过<code>show index from 表名</code>就会发现实际还是B+树</p></blockquote><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTs2PYjO23U0vVzcyGAynugM0AZq9iblYWiaNNeD3jGInSicWCqolQoIseAg/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>在存储引擎中，Memory引擎支持Hash索引</p><blockquote><p>Hash索引其实有点像Java中的HashMap底层的数据结构，他也有很多的槽，存的也是键值对，键值为索引列，值为数据的这条数据的行指针，通过行指针就可以找到数据</p></blockquote><blockquote><p>假设现在<code>user</code>表用Memory存储引擎，对name字段建立Hash索引，表中插入三条数据</p></blockquote><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTs2ZqrovyufsuS8Qou52kWAEGnfGxEnnNjAcabHCJSHEFs80Q5uucCmQ/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><blockquote><p>Hash索引会对索引列name的值进行Hash计算，然后找到对应的槽下面，如下图所示</p></blockquote><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTs7piaeDiarzjlazviaYCpIiccxSCuxnsKD73xduicwWPvYbFg1Ry32wgewfA/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><blockquote><p>当遇到name字段的Hash值相同时，也就是Hash冲突，就会形成一个链表，比如有name=张三有两条数据，就会形成一个链表。</p></blockquote><blockquote><p>之后如果要查name=李四的数据，只需要对李四进行Hash计算，找到对应的槽，遍历链表，取出name=李四对应的行指针，然后根据行指针去查找对应的数据。</p></blockquote><p><strong>Hash索引优缺点</strong></p><ul><li>hash索引只能用于等值比较，所以查询效率非常高</li><li>不支持范围查询，也不支持排序，因为索引列的分布是无序的</li></ul><h3 id="b-树" tabindex="-1">B+树 <a class="header-anchor" href="#b-树" aria-label="Permalink to &quot;B+树&quot;">​</a></h3><p>B+树是mysql索引中用的最多的数据结构，这里先不介绍，下一节会着重介绍。</p><blockquote><p>除了Hash和B+树之外，还有全文索引等其它索引，这里就不讨论了</p></blockquote><h2 id="聚簇索引-1" tabindex="-1">聚簇索引 <a class="header-anchor" href="#聚簇索引-1" aria-label="Permalink to &quot;聚簇索引&quot;">​</a></h2><h3 id="数据页数据存储" tabindex="-1">数据页数据存储 <a class="header-anchor" href="#数据页数据存储" aria-label="Permalink to &quot;数据页数据存储&quot;">​</a></h3><p>我们知道，我们插入表的数据其实最终都要持久化到磁盘上，InnoDB为了方便管理这些数据，提出了<strong>页</strong>的概念，它会将数据划分到多个页中，每个页大小默认是16KB，这个页我们可以称为数据页。</p><p>当我们插入一条数据的时候，数据都会存在数据页中，如下图所示</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTssKJzxpjJxJs0qyiciaMck7V2vxkc4s6pxHdFUiaH4BMAuACUxkrCtfKCA/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>当数据不断地插入数据页中，数据会根据主键（没有的话会自动生成）的大小进行排序，形成一个单向链表</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTs601MDPh0kCPMiaROuAU3jKrpVRbYIia8lkjNPaIL5HSzdbW2Nj4Wf6Tg/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><blockquote><p>数据页中除了会存储我们插入的数据之外，还会有一部分空间用来存储额外的信息，额外的信息类型比较多，后面遇到一个说一个</p></blockquote><h3 id="单个数据页的数据查找" tabindex="-1">单个数据页的数据查找 <a class="header-anchor" href="#单个数据页的数据查找" aria-label="Permalink to &quot;单个数据页的数据查找&quot;">​</a></h3><p>既然数据会存在数据页中，那么该如何从数据页中去查数据呢？</p><p>假设现在需要在数据页中定位到id=2的这条记录的数据，如何快速定位？</p><p>有一种笨办法就是从头开始顺着链表遍历就行了，判断id是不是等于2，如果等于2就取出数据就行了。</p><p>虽然这种方法可行，但是如果一个数据页存储的数据多，几十或者是几百条数据，每次都这么遍历，不是太麻烦了</p><p>所以mysql想了一个好办法，那就是给这些数据分组</p><p>假设数据页中存了12条数据，那么整个分组大致如下图所示</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTssCqQ41YNmKwIKiajfZxWeRxjm3oCJQNquvgzYBialsV5z7B8HAia3IbqQ/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>为了方便了，我这里只标出了id值，省略了其它字段的值</p><p>这里我假设每4条数据算一个组，图上就有3个组，组分好之后，mysql会取出每组中<strong>最大的id</strong>值，就是图中的4、8、12，放在一起，在数据页中找个位置存起来，这就是前面提到的数据页存储的额外信息之一，被称为<strong>页目录</strong></p><p>假设此时要查询id=6的数据之后，此时只需要从页目录中根据二分查找，发现在4-8之间，由于4和8是他们所在分组的最大的id，那么id=6肯定在8那个分组中，之后就会到id=8的那个分组中，遍历每个数据，判断id是不是等于6即可。</p><p>由于mysql规定每个组的数据条数大概为4~8条，所以肯定比遍历整个数据页的数据快的多</p><blockquote><p>上面分组的情况实际上我做了一点简化，但是不耽误理解</p></blockquote><h3 id="多个数据页中的数据查找" tabindex="-1">多个数据页中的数据查找 <a class="header-anchor" href="#多个数据页中的数据查找" aria-label="Permalink to &quot;多个数据页中的数据查找&quot;">​</a></h3><p>当我们不断的往表中插入数据的时候，数据占用空间就会不断变大，但是一个数据页的大小是一定的，当一个数据页存不下数据的时候，就会重新创建一个数据页来存储数据</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTsIPtFyOWayicPS0iaibayU4ZjHw6pibRFuhfNo6UO5iccx0FJcMrq7vGY0wg/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>mysql为了区分每个页，会为每个数据页分配一个页号，存在额外信息的存储空间中，同时额外信息还会存储当前数据页的前一个和后一个数据页的位置，从而形成数据页之间的双向链表</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTstX1GLbibT1ov9psmia64qSKNnZIxlAEmoaI5LvDp4mdOMeG0wntyO5Ug/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>数据页2的页号就是2，数据页3的页号就是3，这里我为了方便理解，就直接写数据页几。</p><p>并且mysql规定，前一个数据页的存储数据id的最大值要小于后一个数据页的存储数据id的最小值，这样就实现了数据在所有数据页中<strong>按照id的大小排序</strong>。</p><p>现在，如果有多个数据页，当我们需要查找id=5的数据，怎么办呢？</p><p>当然还是可以用上面的笨办法，那就是从第一个数据页开始遍历，然后遍历每个数据页中的数据，最终也可以找到id=5的数据。</p><p>但是你仔细想想，这个笨办法就相当于全表扫描了呀，这肯定是不行的。</p><p>那么怎么优化呢？</p><p>mysql优化的思路其实跟前面单数据页查找数据的优化思路差不多</p><p>它会将每个数据页中<strong>最小的id</strong>拿出来，单独放到另一个数据页中，这个数据页不存储我们实际插入的数据，只存储<strong>最小的id</strong>和这个id所在数据页的页号，如图所示</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTsNGibnTRvZkXQlsutD0LNzy0tVpAOtt35oRPibvAOELyxT8hkavXHyB7g/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>为了图更加饱满，我加了一个存放数据的数据页4</p><p>此时数据页5就是抽取出来的，存放了下面三个存放数据的数据页的最小的id和对应的数据页号</p><p>如果此时查找id=5的数据就很方便了，大致分为以下几个步骤：</p><ul><li>从数据页5直接根据二分查找，发现在4-7之间</li><li>由于4和7是所在数据页最小的id，那么此时id=5的数据必在id=4的数据页上(因为id=7的数据页最小的id就是7)，</li><li>接下来就到id=4对应的数据页2的页号找到数据页2</li><li>之后再根据前面提到的根据数据的主键id从单个数据页查找的流程查找数据</li></ul><p>这样就实现了根据主键id到在多个数据页之间查找数据</p><h3 id="聚簇索引-2" tabindex="-1">聚簇索引 <a class="header-anchor" href="#聚簇索引-2" aria-label="Permalink to &quot;聚簇索引&quot;">​</a></h3><p>随着数据量不断增多，存储数据的数据页不断变多，数据页5的数据就会越来越多，但是每个数据页默认就16k，所以数据页5也会分裂出多个数据页的情况，如下图</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTs9JQmEpx1xu58SDXsaqpWicdKoM68ia6z2lS73vicOh9nick879T7MlLvwA/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>数据页10的作用就跟数据页5是一样的</p><p>此时如还要查找id=5的数据，那么应该去数据页5进行二分查找呢还是去数据页10进行二分查找呢？</p><p>笨办法就是遍历，但是真没必要，mysql会去抽取数据页5和数据页10存储的最小的数据的id和对应的数据页号，单独拎出来放到一个数据页中，如下图</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTsbMRfnERT85s2mYJgxnEfgnibkgpNoibgDhfukI64nyYFZ9S68EibKHdtQ/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>数据页11就是新抽取的数据页，存储了id=1和对应的数据页5的页号以及数id=10和对应的数据页10的页号</p><p>而这就是<strong>B+树</strong>。</p><blockquote><p>一般来说，mysql数据库的B+树一般三层就可以放下几千万条数据</p></blockquote><p>此时查找id=5的数据，大致分为以下几个步骤：</p><ul><li>从数据页11根据二分查找定位到id=5对应数据页5</li><li>再到数据页5根据id=5二分查找定位到数据页3</li><li>再到数据页3根据id=5查找数据，具体的逻辑前面也提到很多次了</li></ul><p>这样就能成功查找到数据了</p><p>而这种叶子节点存储实际插入的数据的B+树就被称为<strong>聚簇索引</strong>，非叶子节点存储的就是记录的id和对应的数据页号。</p><p>所以对于InnoDB存储引擎来说，数据本身就存储在一颗B+树中。</p><h2 id="二级索引" tabindex="-1">二级索引 <a class="header-anchor" href="#二级索引" aria-label="Permalink to &quot;二级索引&quot;">​</a></h2><p>二级索引也被称为非聚簇索引，本身也就是一颗B+树，一个二级索引对应一颗B+树，但是二级索引B+树存储的数据跟聚簇索引不一样。</p><p>聚簇索引前面也说了，叶子节点存的就是我们插入到数据库的数据，非叶子节点存的就是数据的主键id和对应的数据页号。</p><p>而二级索引叶子节点存的是索引列的数据和对应的主键id，非叶子节点除了索引列的数据和id之外，还会存数据页的页号。</p><blockquote><p>前面提到的数据页，其实真正是叫索引页，因为叶子节点存的是实际表的数据，所以我就叫数据页了，接下来因为真正要讲到索引了，所以我就将二级索引的页称为索引页，你知道是同一个，但是存储的数据不一样就可以了。</p></blockquote><h3 id="单列索引" tabindex="-1">单列索引 <a class="header-anchor" href="#单列索引" aria-label="Permalink to &quot;单列索引&quot;">​</a></h3><p>假设，我们现在对name字段加了一个普通非唯一索引，那么name就是索引列，同时name这个索引也就是单列索引</p><p>此时如果往表中插入三条数据，那么name索引的叶子节点存的数据就如下图所示</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTsibIXXOFOiauUwMkrLgxEsXeqhB947L4Mib90KDcUYuwDryRqvSY8Px9KQ/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p><strong>mysql会根据name字段的值进行排序，这里我假设张三排在李四前面，当索引列的值相同时，就会根据id排序，所以索引实际上已经根据索引列的值排好序了。</strong></p><p>这里肯定有小伙伴疑问，name字段存储的中文也可以排序么？</p><p>答案是可以的，并且mysql支持很多种排序规则，我们在建数据库或者是建表的时候等都可以指定排序规则，<strong>并且后面文章涉及到的字符串排序都是我随便排的，实际情况可能不一样</strong>。</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTs9oFETicgVicwPTXHfKqjyBus1HTPhic4vSWC6ribTFxliavIFm2YGFffQ6Q/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>对于单个索引列数据查找也是跟前面说的聚簇索引一样，也会对数据分组，之后可以根据二分查找在单个索引列来查找数据。</p><p>当数据不断增多，一个索引页存储不下数据的时候，也会用多个索引页来存储，并且索引页直接也会形成双向链表</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTs9nibCgLXcu2EzAHm22eSYBsKs9oYpMgcWCg9ZQrALQmrxNaCbJVFCxw/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>当索引页不断增多是，为了方便在不同索引页中查找数据，也就会抽取一个索引页，除了存页中id，同时也会存储这个id对应的索引列的值</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTs1okyBK5ANeqGia4dQ6kwC9rCLXE6GkhCbXJ7l7e1QD6uZgNJ3pvUKKA/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>当数据越来越多越来越多，还会抽取，也会形成三层的一个B+树，这里我就不画了。</p><h3 id="联合索引" tabindex="-1">联合索引 <a class="header-anchor" href="#联合索引" aria-label="Permalink to &quot;联合索引&quot;">​</a></h3><p>除了单列索引，联合索引其实也是一样的，只不过索引页存的数据就多了一些索引列</p><p>比如，在name和age上建立一个联合索引，此时单个索引页就如图所示</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTshgfdOz7dkvW5lFMFwItzs77V0y2hv0EicNU7p1DTstaZATy5ZXmgppQ/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p><strong>先以name排序，name相同时再以age排序，如果再有其它列，依次类推，最后再以id排序。</strong></p><p>相比于只有name一个字段的索引来说，索引页就多存了一个索引列。</p><p>最后形成的B+树简化为如下图</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTsfNKjBY4FMenPN8vFuXqey8PwKSeUH1Ly7dBFlLiao7SR3DqDEVUYl1Q/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><h3 id="小结" tabindex="-1">小结 <a class="header-anchor" href="#小结" aria-label="Permalink to &quot;小结&quot;">​</a></h3><p>其实从上面的分析可以看出，聚簇索引和非聚簇索引主要区别有以下几点</p><ul><li>聚簇索引的叶子节点存的是所有列的值，非聚簇索引的叶子节点只存了索引列的值和主键id</li><li>聚簇索引的数据是按照id排序，非聚簇索引的数据是按照索引列排序</li><li>聚簇索引的非叶子节点存的是主键id和页号，非聚簇索引的非叶子节点存的是索引列、主键id、页号</li></ul><p>由于后面这个索引树会经常用到，为了你方便比较，所以我根据上面索引树的数据在表中插入了对应的数据，sql在文末</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTsIEo8Jg4w8RQSM0YeQxE3TOpxsekqA0icltgsArMXexXEQglOQic2Kybg/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>实际情况下索引B+树可能并不是按照我图中画出来的那样排序，但不耽误理解。</p><h2 id="回表" tabindex="-1">回表 <a class="header-anchor" href="#回表" aria-label="Permalink to &quot;回表&quot;">​</a></h2><p>讲完二级索引，接下来讲一讲如何使用二级索引查找数据。</p><p>这里假设对name字段创建了一个索引，并且表里就存了上面示例中的几条数据，这里我再把图拿过来</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTs1okyBK5ANeqGia4dQ6kwC9rCLXE6GkhCbXJ7l7e1QD6uZgNJ3pvUKKA/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>那么对于下面这条sql应该如何执行？</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">select * from `user` where name = &#39;赵六&#39;;</span></span></code></pre></div><p>由于查询条件是<code>name = &#39;赵六&#39;</code>，所以会走name索引</p><p>整个过程大致分为以下几个步骤：</p><ul><li>从最上面那层索引页开始二分查找，我们图中就是索引页113，如果索引页113上面还有一层，就从上面一层二分查找</li><li>在索引页113查找到<code>赵六</code>在<code>王五</code>和<code>刘七</code>之间，之后到<code>王五</code>对应的索引页111上去查找<code>赵六</code></li><li>在索引页111找到<code>赵六</code>的第一条记录，也就是id=4的那条</li><li>由于是<code>select *</code>，还要查其它字段，此时就会根据id=4到聚簇索引中查找其它字段数据，这个查找过程前面说了很多次了，这个根据id=4到聚簇索引中查找数据的过程就被称为<strong>回表</strong></li><li>由于是非唯一索引，所以<code>赵六</code>这个值可能会有重复，所以接着就会在索引页111顺着链表继续遍历，如果name还是<code>赵六</code>，那么还会根据id值进行回表，如此重复，一直这么遍历，直至name不再等于<code>赵六</code>为止，对于图示，其实就是两条数据</li></ul><p>从上面的二级索引的查找数据过程分析，就明白了<strong>回表</strong>的意思，就是先从二级索引根据查询条件字段值查找对应的主键id，之后根据id再到聚簇索引查找其它字段的值。</p><h2 id="覆盖索引" tabindex="-1">覆盖索引 <a class="header-anchor" href="#覆盖索引" aria-label="Permalink to &quot;覆盖索引&quot;">​</a></h2><p>上一节说当执行<code>select * from user where name = &#39;赵六&#39;;</code>这条sql的时候，会先从索引页中查出来<code>name = &#39;赵六&#39;;</code>对应的主键id，之后再回表，到聚簇索引中查询其它字段的值。</p><p>那么当执行下面这条sql，又会怎样呢？</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">select id from `user` where name = &#39;赵六&#39;;</span></span></code></pre></div><p>这次查询字段从<code>select *</code>变成<code>select id</code>，查询条件不变，所以也会走name索引</p><p>所以还是跟前面一样了，先从索引页中查出来<code>name = &#39;赵六&#39;;</code>对应的主键id之后，惊讶的发现，sql中需要查询字段的id值已经查到了，那次此时压根就不需要回表了，已经查到id了，还回什么表。</p><p>而这种需要查询的字段都在索引列中的情况就被称为<strong>覆盖索引</strong>，索引列覆盖了查询字段的意思。</p><p>当使用覆盖索引时会减少回表的次数，这样查询速度更快，性能更高。</p><blockquote><p>所以，在日常开发中，尽量不要select * ，需要什么查什么，如果出现覆盖索引的情况，查询会快很多。</p></blockquote><h2 id="索引下推" tabindex="-1">索引下推 <a class="header-anchor" href="#索引下推" aria-label="Permalink to &quot;索引下推&quot;">​</a></h2><p>假设现在对表建立了一个name和age的联合索引，为了方便理解，我把前面的图再拿过来</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTsfNKjBY4FMenPN8vFuXqey8PwKSeUH1Ly7dBFlLiao7SR3DqDEVUYl1Q/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>接下来要执行如下的sql</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">select * from `user` where name &gt; &#39;王五&#39; and age &gt; 22;</span></span></code></pre></div><p>在MySQL5.6(不包括5.6)之前，整个sql大致执行步骤如下：</p><ul><li>先根据二分查找，定位到<code>name &gt; &#39;王五&#39;</code>的第一条数据，也就是id=4的那个赵六</li><li>之后就会根据id=4进行回表操作，到聚簇索引中查找id=4其它字段的数据，然后判断数据中的age是否大于22，是的话就说明是我们需要查找的数据，否则就不是</li><li>之后顺着链表，继续遍历，然后找到一条记录就回一次表，然后判断age，如此反复下去，直至结束</li></ul><p>所以对于图上所示，整个搜索过程会经历5次回表操作，两个赵六，两个刘七，一个王九，最后符合条件的也就是id=6的赵六那条数据，其余age不符和。</p><p>虽然这么执行没什么问题，但是不知有没有发现其实没必要进行那么多次回表，因为光从上面的索引图示就可以看出，符合<code>name &gt; &#39;王五&#39; and age &gt; 22</code>的数据就id=6的赵六那条数据</p><p>所以在MySQL5.6之后，对上面的<code>age &gt; 22</code>判断逻辑进行了优化</p><p>前面还是一样，定位查找到id=4的那个赵六，之后就<strong>不回表</strong>来判断age了，因为索引列有age的值了，那么直接根据索引中age判断是否大于22，如果大于的话，再回表查询剩余的字段数据（因为是<code>select *</code>），然后再顺序链表遍历，直至结束</p><p>所以这样优化之后，回表次数就成1了，相比于前面的5次，大大减少了回表的次数。</p><p>而这个优化，就被称为<strong>索引下推</strong>，就是为了减少回表的次数。</p><blockquote><p>之所以这个优化叫索引下推，其实是跟判断<code>age &gt; 22</code>逻辑执行的地方有关，这里就不过多赘述了。</p></blockquote><h2 id="索引合并" tabindex="-1">索引合并 <a class="header-anchor" href="#索引合并" aria-label="Permalink to &quot;索引合并&quot;">​</a></h2><p>索引合并（index merge）是从MySQL5.1开始引入的索引优化机制，在之前的MySQL版本中，一条sql多个查询条件只能使用一个索引，但是引入了索引合并机制之后，MySQL在<strong>某些特殊</strong>的情况下会扫描多个索引，然后将扫描结果进行合并</p><p>结果合并会为下面三种情况：</p><ul><li>取交集（intersect）</li><li>取并集（union）</li><li>排序后取并集（sort-union）</li></ul><p>为了不耽误演示，删除之前所有的索引，然后为name和age各自分别创建一个二级索引idx_name和idx_age</p><h4 id="取交集-intersect" tabindex="-1">取交集（intersect） <a class="header-anchor" href="#取交集-intersect" aria-label="Permalink to &quot;取交集（intersect）&quot;">​</a></h4><p>当执行下面这条sql就会出现取交集的情况</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">select * from `user` where name = &#39;赵六&#39; and age= 22;</span></span></code></pre></div><p>查看执行计划</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTsic3XoytmcE6iaCAgVZBfXP9dwaA9ApAkKF9w7a5wwKRF4YlEIy85YqxQ/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>type是<code>index_merge</code>，并且possible_key和key都是<code>idx_name</code>和<code>idx_age</code>，说明使用了索引合并，并且Extra有<code>Using intersect(idx_age,idx_name)</code>，intersect就是交集的意思。</p><p>整个过程大致是这样的，分别根据<code>idx_name</code>和<code>idx_age</code>取出对应的主键id，之后将主键id取交集，那么这部分交集的id一定同时满足查询<code>name = &#39;赵六&#39; and age= 22</code>的查询条件（仔细想想），之后再根据交集的id回表</p><p>不过要想使用取交集的联合索引，需要满足各自索引查出来的主键id是排好序的，这是为了方便可以快速的取交集</p><p>比如下面这条sql就无法使用联合索引</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">select * from `user` where name = &#39;赵六&#39; and age &gt; 22;</span></span></code></pre></div><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTsGhZwcg6Dgv9XFcEhSFT9EIA0gnYyXjybicg17MGuWJ9IEECaRT9ynFw/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>只能用name这个索引，因为<code>age &gt; 22</code>查出来的id是无序的，前面在讲索引的时候有说过索引列的排序规则</p><p>由此可以看出，使用联合索引条件还是比较苛刻的。</p><h4 id="取并集-union" tabindex="-1">取并集（union） <a class="header-anchor" href="#取并集-union" aria-label="Permalink to &quot;取并集（union）&quot;">​</a></h4><p>取并集就是将前面例子中的<code>and</code>换成<code>or</code></p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">select * from `user` where name = &#39;赵六&#39; or age = 22;</span></span></code></pre></div><p>前面执行的情况都一样，根据条件到各自的索引上去查，之后对查询的id取并集去重，之后再回表</p><p>同样地，取并集也要求各自索引查出来的主键id是排好序的，如果查询条件换成<code>age &gt; 22</code>时就无法使用取并集的索引合并</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">select * from `user` where name = &#39;赵六&#39; or age &gt; 22;</span></span></code></pre></div><h4 id="排序后取并集-sort-union" tabindex="-1">排序后取并集（sort-union） <a class="header-anchor" href="#排序后取并集-sort-union" aria-label="Permalink to &quot;排序后取并集（sort-union）&quot;">​</a></h4><p>虽然取并集要求各自索引查出来的主键id是排好序的，但是如果遇到没排好序的情况，mysql会自动对这种情况进行优化，会先对主键id排序，然后再取并集，这种情况就叫 排序后取并集（sort-union）。</p><p>比如上面提到的无法直接取并集的sql就符合排序后取并集（sort-union）这种情况</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">select * from `user` where name = &#39;赵六&#39; or age &gt; 22;</span></span></code></pre></div><h2 id="mysql如何选择索引" tabindex="-1">mysql如何选择索引 <a class="header-anchor" href="#mysql如何选择索引" aria-label="Permalink to &quot;mysql如何选择索引&quot;">​</a></h2><p>在日常生产中，一个表可能会存在多个索引，那么mysql在执行sql的时候是如何去判断该走哪个索引，或者是全表扫描呢？</p><p>mysql在选择索引的时候会根据索引的使用成本来判断</p><p>一条sql执行的成本大致分为两块</p><ul><li>IO成本，因为这些页都是在磁盘的，要想去判断首先得加载到内存，MySQL规定加载一个页的成本为1.0</li><li>CPU成本，除了IO成本之外，还有条件判断的成本，也就是CPU成本。比如前面举的例子，你得判断加载的数据<code>name = &#39;赵六&#39;</code>符不符合条件，MySQL规定每判断一条数据花费的成本为0.2</li></ul><h4 id="全表扫描成本计算" tabindex="-1">全表扫描成本计算 <a class="header-anchor" href="#全表扫描成本计算" aria-label="Permalink to &quot;全表扫描成本计算&quot;">​</a></h4><p>对于全表扫描来说，成本计算大致如下</p><p>mysql会对表进行数据统计，这个统计是大概，不是特别准，通过<code>show table status like &#39;表名&#39;</code>可以查看统计数据</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTsGVgpq1PdaE7ZckBXAlw9bhiabONDhbkuvEXEKUrjPicZC7xv1fhuxk1Q/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>比如这个表大致有多少条数据rows，以及聚簇索引所占的字节数data_length，由于默认是16kb，所以就可以计算出(data_length/1024/16)大概有多少个数据页。</p><p>所以全表扫描的成本就这么计算了</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">rows * 0.2 + data_length/1024/16 * 1.0</span></span></code></pre></div><h4 id="二级索引-回表成本计算" tabindex="-1">二级索引+回表成本计算 <a class="header-anchor" href="#二级索引-回表成本计算" aria-label="Permalink to &quot;二级索引+回表成本计算&quot;">​</a></h4><p>二级索引+回表成本计算比较复杂，他的成本数据依赖两部分扫描区间个数和回表次数</p><p>为了方便描述扫描区间，这里我再把上面的图拿上来</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTsfNKjBY4FMenPN8vFuXqey8PwKSeUH1Ly7dBFlLiao7SR3DqDEVUYl1Q/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">select * from `user` where name = &#39;赵六&#39;;</span></span></code></pre></div><p>对着图看！</p><p>查询条件<code>name = &#39;赵六&#39;</code>就会产生一个扫描区间，从id=4的赵六扫描到id=6的赵六</p><p>又比如假设查询条件为<code>name &gt; &#39;赵六&#39;</code>，此时就会产生一个从id=7的刘七开始直到数据结束（id=9的王九）的扫描区间</p><p>又比如假设查询条件为<code>name &lt; &#39;李四&#39; and name &gt; &#39;赵六&#39;</code>，此时就会产生两个扫描区间，从id=2的张三到id=3的张三算一个，从id=7的刘七开始直到数据结束算另一个</p><p>所以扫描区间的意思就是符合查询条件的记录区间</p><p>二级索引计算成本的时候，mysq规定读取一个区间的成本跟读取一个页的IO成本是一样的，都是1.0</p><p>区间有了之后，就会根据统计数据估计在这些区间大致有多少条数据，因为要读写这些数据，那么读取成本大致就是 条数 * 0.2</p><p>所以走二级索引的成本就是 <code>区间个数 * 1.0 + 条数 * 0.2</code></p><p>之后这些数据需要回表（如果需要的话），mysql规定每次回表也跟读取一个页的IO成本是一样，也是1.0</p><p>回表的时候需要对从聚簇索引查出来的数据进行剩余查询条件的判断，就是CPU成本，大致为 条数 * 0.2</p><p>所以回表的成本大致为 <code>条数 * 1.0 + 条数 * 0.2</code></p><p>所以二级索引+回表的大致成本为 <code>区间个数 * 1.0 + 条数 * 0.2 + 条数 * 1.0 + 条数 * 0.2</code></p><p>当索引的成本和全表扫描的成本都计算完成之后，mysql会选择成本最低的索引来执行</p><blockquote><p>mysql对上述成本计算结果还会微调，但是微调的值特别小，所以这里我就省略了，并且这里也只是大致介绍了成本计算的规则，实际情况会更复杂，比如连表查询等等，有感兴趣的小伙伴查阅相关的资料</p></blockquote><h4 id="小结-1" tabindex="-1">小结 <a class="header-anchor" href="#小结-1" aria-label="Permalink to &quot;小结&quot;">​</a></h4><p>总的来说，这一节主要是让你明白一件事，mysql在选择索引的时候，会根据统计数据和成本计算的规则来计算使用每个索引的成本，然后选择使用最低成本的索引来执行查询</p><h2 id="索引失效" tabindex="-1">索引失效 <a class="header-anchor" href="#索引失效" aria-label="Permalink to &quot;索引失效&quot;">​</a></h2><p>在日常开发中，肯定或多或少都遇到过索引失效的问题，这里我总结一下几种常见的索引失效的场景</p><p>为了方便解释，这里我再把图拿过来</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTsfNKjBY4FMenPN8vFuXqey8PwKSeUH1Ly7dBFlLiao7SR3DqDEVUYl1Q/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><h5 id="不符和最左前缀匹配原则" tabindex="-1">不符和最左前缀匹配原则 <a class="header-anchor" href="#不符和最左前缀匹配原则" aria-label="Permalink to &quot;不符和最左前缀匹配原则&quot;">​</a></h5><p>当不符和最左前缀匹配原则的时候会导致索引失效</p><p>比如<code>like</code>以%开头，索引失效或者是联合索引没走第一个索引列。</p><p>比如name和age的联合索引，当执行<code>select * from user where name &gt; &#39;王五&#39; and age &gt; 22;</code>时，那么如果要走索引的话，此时就需要扫描整个索引，因为索引列是先以name字段排序，再以age字段排序的，对于age来说，在整个索引中来说是无序的，从图中也可以看出 18、23...9，无序，所以无法根据二分查找定位到<code>age &gt; 22</code>是从哪个索引页开始的，</p><p>所以走索引的话要扫描整个索引，一个一个判断，最后还要回表，这就很耗性能，不如直接扫描聚簇索引，也就是全表扫描来的痛快。</p><h5 id="索引列进行了计算" tabindex="-1">索引列进行了计算 <a class="header-anchor" href="#索引列进行了计算" aria-label="Permalink to &quot;索引列进行了计算&quot;">​</a></h5><p>当对索引进行表达式计算或者使用函数时也会导致索引失效</p><p>这个主要是因为索引中保存的是索引字段是原始值，从上面画的图可以看出来，当经过函数计算后的值，也就没办法走索引了</p><h5 id="隐式转换" tabindex="-1">隐式转换 <a class="header-anchor" href="#隐式转换" aria-label="Permalink to &quot;隐式转换&quot;">​</a></h5><p>当索引列发生了隐式转换<strong>可能会</strong>导致索引失效</p><p>举个例子，mysql规定，当字符串跟数字比较时，会把字符串先转成数字再比较，至于字符串怎么转成数字，mysql有自己的规则</p><p>比如说，当我执行了下面这条sql时就会发生隐式转换</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">select * from `user` where name = 9527;</span></span></code></pre></div><p>name字段是个varchar类型，9527，没加引号，是数字，mysql根据规则会把<code>name</code>字段的值先转换成数字，再与9527比较，此时由于<code>name</code>字段发生了转换，所以索引失效了</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTsw9P4oibicClPCswFwrD4Yqx482iaw13nwpo0aYoBFIYU3Vg727FZrDo3Q/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>ALL说明没走索引，失效了。</p><p>但是假设现在对age创建一个索引，执行下面这条sql</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">select * from `user` where age = &#39;22&#39;;</span></span></code></pre></div><p>此时age索引就不会失效，主要是因为前面说的那句话：</p><p>当字符串跟数字比较时，会把字符串先转成数字再比较</p><p>于是<code>&#39;22&#39;</code>会被隐式转成数字，之后再跟age比较，此时age字段并没有发生隐式转换，所以不会失效。</p><p>所以说，隐式转换<strong>可能会</strong>导致索引失效。</p><h5 id="mysql统计数据误差较大" tabindex="-1">mysql统计数据误差较大 <a class="header-anchor" href="#mysql统计数据误差较大" aria-label="Permalink to &quot;mysql统计数据误差较大&quot;">​</a></h5><p>mysql统计数据误差较大也可能会导致索引失效，因为前面也说了，mysql会根据统计数据来计算使用索引的成本，这样一旦统计数据误差较大，那么计算出来的成本误差就大，就可能出现实际走索引的成本小但是计算出来的是走索引的成本大，导致索引失效</p><p>当出现这种情况时，可以执行<code>analyze table 表名</code>这条sql，mysql就会重新统计这些数据，索引就可以重新生效了</p><h2 id="索引建立原则" tabindex="-1">索引建立原则 <a class="header-anchor" href="#索引建立原则" aria-label="Permalink to &quot;索引建立原则&quot;">​</a></h2><h4 id="单个表索引数量不宜过多" tabindex="-1">单个表索引数量不宜过多 <a class="header-anchor" href="#单个表索引数量不宜过多" aria-label="Permalink to &quot;单个表索引数量不宜过多&quot;">​</a></h4><ul><li>从上面分析我们知道，每个索引都对应一颗B+树，并且叶子节点存储了索引列全量的数据，一旦索引数量多，那么就会占有大量磁盘空间</li><li>同时前面也提到，在查询之前会对索引成本进行计算，一旦索引多，计算的次数就多，也可能会浪费性能</li></ul><h4 id="经常出现在where后的字段应该建立索引" tabindex="-1">经常出现在where后的字段应该建立索引 <a class="header-anchor" href="#经常出现在where后的字段应该建立索引" aria-label="Permalink to &quot;经常出现在where后的字段应该建立索引&quot;">​</a></h4><p>这个就不用说了，索引就是为了加快速度，如果没有合适索引，就会全表扫描，对于InnoDB来说，全表扫描就是从聚簇索引的第一个叶子节点开始，顺着链表一个一个判断数据服不服合查询条件</p><h4 id="order-by、group-by后字段可建立索引" tabindex="-1">order by、group by后字段可建立索引 <a class="header-anchor" href="#order-by、group-by后字段可建立索引" aria-label="Permalink to &quot;order by、group by后字段可建立索引&quot;">​</a></h4><p>比如下面这条sql</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">select * from `user` where name = &#39;赵六&#39; order by age asc;</span></span></code></pre></div><p>查询<code>name = &#39;赵六&#39;</code>并且根据<code>age</code>排序，name和age联合索引</p><p>你可能记不清索树了，我把那个索引树拿过来</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTsfNKjBY4FMenPN8vFuXqey8PwKSeUH1Ly7dBFlLiao7SR3DqDEVUYl1Q/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>此时对着索引树你可以发现，当<code>name = &#39;赵六&#39;</code>时，<code>age</code>已经排好序了（前面介绍索引的说了排序规则），所以就可以使用<code>age</code>索引列进行排序。</p><h4 id="频繁更新的字段不宜建索引" tabindex="-1">频繁更新的字段不宜建索引 <a class="header-anchor" href="#频繁更新的字段不宜建索引" aria-label="Permalink to &quot;频繁更新的字段不宜建索引&quot;">​</a></h4><p>因为索引需要保证按照索引列的值进行排序，所以一旦索引字段数据频繁更新，那么为了保证索引的顺序，就得频繁挪动索引列在索引页中的位置</p><p>比如name和age联合索引</p><p>此时把id=9这条数据的name从<code>王九</code>改成<code>赵六</code>，那么此时就把这条更改后的数据在索引页上移到王五和id=4的赵六之间，因为name相同时，得保证顺序性，同时要按照age排序，id=9的age为9，最小，那么排在最前。</p><p>所以频繁更新的字段建索引就会增加维护索引的成本。</p><h4 id="选择区分度高的字段做索引" tabindex="-1">选择区分度高的字段做索引 <a class="header-anchor" href="#选择区分度高的字段做索引" aria-label="Permalink to &quot;选择区分度高的字段做索引&quot;">​</a></h4><p>这个是因为，如果区分度低，那么索引效果不好。</p><p>举个例子，假设现在有个性别字段sex，非男即女，如果对sex建索引，假设男排在女之前，那么索引页的数据排列大致如下：</p><p><img src="https://mmbiz.qpic.cn/mmbiz_png/B279WL06QYzWib7icY6CN5Rfr7AZibATpTs7XEiaUIpJXHkB0paKicOG6ia8MEONTAS6xHpQMTef6wrxLwlCibfQPs8Tw/640?wx_fmt=png&amp;wxfrom=5&amp;wx_lazy=1&amp;wx_co=1" alt="图片"></p><p>这里我画了6条数据，假设有10w条数据那么也是这继续排，男在前，女子在后。</p><p>此时如果走sex索引，查询sex=男的数据，假设男女数据对半，那么就扫描的记录就有5w，之后如果要回表，那么根据成本计算规则发现成本是巨大的，那么此时还不如直接全表扫描来的痛快。</p><p>所以要选择区分度高的字段做索引</p><h2 id="总结" tabindex="-1">总结 <a class="header-anchor" href="#总结" aria-label="Permalink to &quot;总结&quot;">​</a></h2><p>到这，本文就结束了，这里回顾一下本文讲的内容</p><p>首先主要是讲了聚簇索引和非聚簇索引，随后讲了MySQL对于一些常见查询的优化，比如覆盖索引，索引下推，都是为了减少回表次数，从而减少带来的性能消耗，再后面就提到MySQL是如何选择索引的，最后介绍了索引失效的场景和索引建立的原则。</p><p>最后希望本文对你有所帮助！</p><p>最后的最后，表数据sql如下</p><div class="language-"><button title="Copy Code" class="copy"></button><span class="lang"></span><pre class="shiki material-theme-palenight"><code><span class="line"><span style="color:#A6ACCD;">INSERT INTO `user` (`id`, `name`, `age`, `city`) VALUES (1, &#39;李四&#39;, 20, &#39;杭州&#39;);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO `user` (`id`, `name`, `age`, `city`) VALUES (2, &#39;张三&#39;, 18, &#39;北京&#39;);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO `user` (`id`, `name`, `age`, `city`) VALUES (3, &#39;张三&#39;, 23, &#39;上海&#39;);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO `user` (`id`, `name`, `age`, `city`) VALUES (4, &#39;赵六&#39;, 22, &#39;杭州&#39;);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO `user` (`id`, `name`, `age`, `city`) VALUES (5, &#39;王五&#39;, 19, &#39;北京&#39;);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO `user` (`id`, `name`, `age`, `city`) VALUES (6, &#39;赵六&#39;, 24, &#39;上海&#39;);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO `user` (`id`, `name`, `age`, `city`) VALUES (7, &#39;刘七&#39;, 20, &#39;上海&#39;);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO `user` (`id`, `name`, `age`, `city`) VALUES (8, &#39;刘七&#39;, 22, &#39;上海&#39;);</span></span>
<span class="line"><span style="color:#A6ACCD;">INSERT INTO `user` (`id`, `name`, `age`, `city`) VALUES (9, &#39;王九&#39;, 9, &#39;杭州&#39;);</span></span></code></pre></div><p><strong>参考：</strong></p><p>[1].《MySQL是怎样运行的》</p><p>[2].<a href="https://blog.csdn.net/weixin_44953658/article/details/127878350" target="_blank" rel="noreferrer">https://blog.csdn.net/weixin_44953658/article/details/127878350</a></p></div></div></main><footer class="VPDocFooter" data-v-6b87e69f data-v-37656e44><!--[--><!--]--><!----><nav class="prev-next" data-v-37656e44><div class="pager" data-v-37656e44><!----></div><div class="pager" data-v-37656e44><a class="pager-link next" href="/notebook/Java/Java%E5%9F%BA%E7%A1%80.html" data-v-37656e44><span class="desc" data-v-37656e44>Next page</span><span class="title" data-v-37656e44>Java基础</span></a></div></nav></footer><!--[--><!--]--></div></div></div><!--[--><!--]--></div></div><!----><!--[--><!--]--></div></div>
    <script>window.__VP_HASH_MAP__=JSON.parse("{\"2、数据库_mysql_mysql面试_基础.md\":\"40da680a\",\"1、学前端_5、小程序_小程序项目.md\":\"60a1629b\",\"1、学前端_4、node_知识篇.md\":\"a7fb500e\",\"1、学前端_2、js_ts_es6 进阶.md\":\"6d07ba10\",\"1、学前端_3、vue_vue3_vue3进阶.md\":\"7ac622b4\",\"5、运维_jenkins.md\":\"929081f8\",\"1、学前端_2、js_ts_typescript.md\":\"875a4aa4\",\"2、数据库_mysql_mysql核心_设计.md\":\"7faf46d1\",\"2、数据库_mysql_mysql核心_基础.md\":\"d8e97f3e\",\"1、学前端_1、html_css_html基础.md\":\"7584d076\",\"1、学前端_5、专题篇_问题篇.md\":\"e893aaa2\",\"2、数据库_mysql_mysql面试_进阶.md\":\"f934806d\",\"3、springboot_运维_原理.md\":\"f4a39db6\",\"2、数据库_influxdb.md\":\"6e1711e1\",\"3、springboot_新特性.md\":\"cdf3e307\",\"mybatis_mybatisplus_jpa.md\":\"8e41681b\",\"1、学前端_5、小程序_小程序优化.md\":\"a2185198\",\"2、数据库_redis_redis基础.md\":\"856df0e0\",\"linux_实用脚本.md\":\"f2299dd5\",\"4、微服务_必备_分布式基础.md\":\"d49863d5\",\"2、数据库_redis_redis优化.md\":\"e66ae32f\",\"4、微服务_springsecurity_进阶篇.md\":\"235a8e9e\",\"5、运维_chatgpt.md\":\"10db3823\",\"2、数据库_mysql_分库分表.md\":\"e1c8a095\",\"start.md\":\"9bc1ff8d\",\"5、运维_github.md\":\"2ec6c735\",\"java学前端_css.md\":\"f11b47f0\",\"1、学前端_5、专题篇_知识篇.md\":\"a463ed8d\",\"linux_软件部署.md\":\"d6722925\",\"2、数据库_neo4j.md\":\"97ad22ac\",\"team.md\":\"ce467a6a\",\"nginx_实战篇.md\":\"7785486e\",\"index.md\":\"8c3ec167\",\"计算机基础_计算机网络_网络基础.md\":\"7a54a85d\",\"1、学前端_4、node_进阶篇.md\":\"60f6db69\",\"java_java集合.md\":\"a049b313\",\"1、学前端_3、vue_vue3_vue3高级.md\":\"614d1516\",\"1、学前端_5、小程序_微信小程序.md\":\"9a4be771\",\"5、运维_netty.md\":\"12ca0278\",\"2、数据库_mysql_mysql核心_运维.md\":\"83f97c16\",\"idea_vs code.md\":\"afdcb593\",\"java学前端_vue3_组件.md\":\"1086884e\",\"idea_chrome.md\":\"4a32afbc\",\"云原生_k8s.md\":\"db58e65a\",\"2、数据库_mysql_mysql核心_进阶.md\":\"61d16dff\",\"ssm_springbatch.md\":\"f799ab4a\",\"三高_分布式.md\":\"db1b8a1b\",\"2、数据库_elasticsearch_1、es基础.md\":\"04d17448\",\"linux_linux基础.md\":\"4b0bf394\",\"idea_idea插件.md\":\"fa86e45a\",\"可视化 _ 监控_可视化大屏.md\":\"004553bd\",\"2、数据库_mongodb_整合.md\":\"3c47d7f4\",\"4、微服务_springsecurity_基础篇.md\":\"534a3401\",\"4、微服务_进阶.md\":\"69095c58\",\"计算机基础_计算机基础_操作系统.md\":\"0f75d113\",\"可视化 _ 监控_zabbix.md\":\"71f2270e\",\"nginx_基础篇.md\":\"c7d8bb50\",\"1、学前端_4、node_项目实战.md\":\"bc5065b8\",\"2、数据库_redis_redis原理.md\":\"5cedf685\",\"可视化 _ 监控_监控基础.md\":\"ac56ce4d\",\"三高_高并发.md\":\"ea9ffc99\",\"2、数据库_redis_redis高级.md\":\"1d5872f6\",\"1、学前端_4、node_基础篇.md\":\"581cc13a\",\"2、数据库_mongodb_基础.md\":\"fb7a0a29\",\"idea_idea基础.md\":\"6f2f9638\",\"4、微服务_必备_sentinel.md\":\"2edfbf6c\",\"2、数据库_elasticsearch_3、es高级.md\":\"ef146606\",\"1、学前端_3、vue_vue3_vue3新语法.md\":\"8afd5409\",\"消息中间件_canal.md\":\"3949163c\",\"ssm_maven.md\":\"2c5e12ed\",\"4、微服务_springsecurity_高级篇.md\":\"882d3ff3\",\"linux_linux进阶.md\":\"188ef7b4\",\"计算机基础_设计模式_uml.md\":\"634ba256\",\"计算机基础_算法_leetcode.md\":\"77162fb9\",\"项目实战_小兔鲜_进阶篇1.md\":\"17c52c81\",\"1、学前端_2、js_ts_es6 基础.md\":\"fda3f18b\",\"项目实战_小兔鲜_进阶篇2.md\":\"a0f23006\",\"软件测试_测试基础.md\":\"8c1060cd\",\"2、数据库_redis_本地缓存.md\":\"00617fe6\",\"nginx_面试篇.md\":\"e3fb373a\",\"mybatis_mybatisplus_mybatis.md\":\"9239e0ad\",\"linux_shell.md\":\"ae53d83b\",\"2、数据库_mysql_mysql核心_优化.md\":\"36230425\",\"项目实战_项目推荐.md\":\"f9d97630\",\"mybatis_mybatisplus_mybatisplus.md\":\"0030fd35\",\"项目实战_百度地图_进阶篇.md\":\"c8b93267\",\"三高_高可用.md\":\"323840c5\",\"java_java新特性.md\":\"22abf56d\",\"软件测试_压力测试.md\":\"9ab44440\",\"java学前端_html_js.md\":\"e0fcd240\",\"2、数据库_redis_redis实战.md\":\"d6daeeab\",\"nginx_进阶篇.md\":\"e6b63195\",\"三高_秒杀.md\":\"3878bb64\",\"5、运维_git.md\":\"0264925c\",\"java_java进阶.md\":\"e79cb5b4\",\"并发 _ 多线程_基础篇.md\":\"7adbfac5\",\"项目实战_百度地图_基础篇.md\":\"8afa5954\",\"java学前端_react.md\":\"3ec827dd\",\"1、学前端_1、html_css_css基础.md\":\"01b56712\",\"项目实战_小兔鲜_基础篇.md\":\"646f5df5\",\"1、学前端_2、js_ts_js 基础.md\":\"cb13e36f\",\"可视化 _ 监控_监控进阶.md\":\"0cdbc292\",\"计算机基础_设计模式_基础篇.md\":\"51617287\",\"计算机基础_数据结构_基础篇.md\":\"b2bfd8d4\",\"项目实战_苍穹外卖_进阶篇.md\":\"48415e41\",\"ssm_spring.md\":\"ab514659\",\"消息中间件_rabbitmq.md\":\"45b1eb28\",\"1、学前端_1、html_css_网页进阶.md\":\"db998248\",\"消息中间件_kafka.md\":\"b747dabf\",\"云原生_docker.md\":\"983c7ba7\",\"4、微服务_必备_分布式锁.md\":\"5af1cf8d\",\"消息中间件_rocketmq.md\":\"d441da85\",\"项目实战_黑马头条_基础篇.md\":\"b05af3a6\",\"ssm_springmvc.md\":\"81b9714f\",\"项目实战_支付.md\":\"1d7407dd\",\"项目实战_黑马头条_进阶篇2.md\":\"bff0015b\",\"项目实战_黑马头条_进阶篇.md\":\"19f18388\",\"java学前端_vue2_组件.md\":\"58c6b1df\",\"3、springboot_基础篇.md\":\"529c66f4\",\"3、springboot_应用篇.md\":\"8b92aa61\",\"项目实战_黑马头条_高级篇.md\":\"227c08c1\",\"1、学前端_5、小程序_uniapp.md\":\"71a282b4\",\"项目实战_云尚办公_基础篇.md\":\"1fe188ba\",\"并发 _ 多线程_并发完善.md\":\"26619c46\",\"1、学前端_2、js_ts_js 进阶.md\":\"657dfb8f\",\"java_java高级.md\":\"23782d1a\",\"java_java基础.md\":\"86d67c77\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"en-US\",\"dir\":\"ltr\",\"title\":\"VitePress\",\"description\":\"A VitePress site\",\"base\":\"/notebook/\",\"head\":[],\"appearance\":true,\"themeConfig\":{\"algolia\":{\"appId\":\"DW7O63I9IR\",\"apiKey\":\"f8ed758cdb288a8b06542bc35923c1a1\",\"indexName\":\"notebook\"},\"sidebar\":[{\"text\":\"Java\",\"collapsed\":true,\"items\":[{\"text\":\"Java基础\",\"link\":\"/Java/Java基础\"},{\"text\":\"Java新特性\",\"link\":\"/Java/Java新特性\"},{\"text\":\"Java进阶\",\"link\":\"/Java/Java进阶\"},{\"text\":\"Java集合\",\"link\":\"/Java/Java集合\"},{\"text\":\"Java高级\",\"link\":\"/Java/Java高级\"}]},{\"text\":\"Linux\",\"collapsed\":true,\"items\":[{\"text\":\"Linux基础\",\"link\":\"/Linux/Linux基础\"},{\"text\":\"Linux新特性\",\"link\":\"/Linux/Linux进阶\"},{\"text\":\"Shell脚本\",\"link\":\"/Linux/Shell\"},{\"text\":\"实用脚本\",\"link\":\"/Linux/实用脚本\"},{\"text\":\"软件部署\",\"link\":\"/Linux/软件部署\"}]},{\"text\":\"Nginx\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/Nginx/基础篇\"},{\"text\":\"进阶篇\",\"link\":\"/Nginx/进阶篇\"},{\"text\":\"实战篇\",\"link\":\"/Nginx/实战篇\"},{\"text\":\"面试篇\",\"link\":\"/Nginx/面试篇\"}]},{\"text\":\"SSM\",\"collapsed\":true,\"items\":[{\"text\":\"Maven\",\"link\":\"/SSM/Maven\"},{\"text\":\"Spring\",\"link\":\"/SSM/Spring\"},{\"text\":\"SpringMVC\",\"link\":\"/SSM/SpringMVC\"},{\"text\":\"SpringBatch\",\"link\":\"/SSM/SpringBatch\"}]},{\"text\":\"SpringBoot\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/3、SpringBoot/基础篇\"},{\"text\":\"应用篇\",\"link\":\"/3、SpringBoot/应用篇\"},{\"text\":\"新特性\",\"link\":\"/3、SpringBoot/新特性\"},{\"text\":\"运维&原理\",\"link\":\"/3、SpringBoot/运维&原理\"}]},{\"text\":\"SpringCloud\",\"collapsed\":true,\"items\":[{\"text\":\"SpringCloud\",\"link\":\"/4、微服务/进阶\"},{\"text\":\"Sentinel\",\"link\":\"/4、微服务/必备/Sentinel\"}]},{\"text\":\"SpringSecurity\",\"collapsed\":true,\"items\":[{\"text\":\"SpringSecurity基础篇\",\"link\":\"/4、微服务/SpringSecurity/基础篇\"},{\"text\":\"SpringSecurity进阶篇\",\"link\":\"/4、微服务/SpringSecurity/进阶篇\"},{\"text\":\"SpringSecurity高级篇\",\"link\":\"/4、微服务/SpringSecurity/高级篇\"}]},{\"text\":\"Mybatis & MybatisPlus\",\"collapsed\":true,\"items\":[{\"text\":\"Mybatis\",\"link\":\"/Mybatis&MybatisPlus/Mybatis\"},{\"text\":\"MybatisPlus\",\"link\":\"/Mybatis&MybatisPlus/MybatisPlus\"},{\"text\":\"JPA\",\"link\":\"/Mybatis&MybatisPlus/JPA\"}]},{\"text\":\"Git & ChatGPT\",\"collapsed\":true,\"items\":[{\"text\":\"Git\",\"link\":\"/5、运维/Git\"},{\"text\":\"Github\",\"link\":\"/5、运维/Github\"},{\"text\":\"ChatGPT\",\"link\":\"/5、运维/ChatGPT\"},{\"text\":\"Jenkins\",\"link\":\"/5、运维/Jenkins\"},{\"text\":\"Netty\",\"link\":\"/5、运维/Netty\"}]},{\"text\":\"数据库\",\"collapsed\":true,\"items\":[{\"text\":\"MySQL\",\"collapsed\":true,\"items\":[{\"text\":\"MySQL基础\",\"link\":\"/2、数据库/MySQL/MySQL核心/基础\"},{\"text\":\"MySQL进阶\",\"link\":\"/2、数据库/MySQL/MySQL核心/进阶\"},{\"text\":\"MySQL优化\",\"link\":\"/2、数据库/MySQL/MySQL核心/优化\"},{\"text\":\"MySQL设计\",\"link\":\"/2、数据库/MySQL/MySQL核心/设计\"},{\"text\":\"MySQL运维\",\"link\":\"/2、数据库/MySQL/MySQL核心/运维\"},{\"text\":\"分库分表\",\"link\":\"/2、数据库/MySQL/分库分表\"}]},{\"text\":\"Redis\",\"collapsed\":true,\"items\":[{\"text\":\"Redis基础\",\"link\":\"/2、数据库/Redis/Redis基础\"},{\"text\":\"Redis优化\",\"link\":\"/2、数据库/Redis/Redis优化\"},{\"text\":\"Redis原理\",\"link\":\"/2、数据库/Redis/Redis原理\"},{\"text\":\"Redis高级\",\"link\":\"/2、数据库/Redis/Redis高级\"},{\"text\":\"Redis实战\",\"link\":\"/2、数据库/Redis/Redis实战\"},{\"text\":\"本地缓存\",\"link\":\"/2、数据库/Redis/本地缓存\"}]},{\"text\":\"MongoDB\",\"collapsed\":true,\"items\":[{\"text\":\"MongoDB基础\",\"link\":\"/2、数据库/MongoDB/基础\"},{\"text\":\"MongoDB进阶\",\"link\":\"/2、数据库/MongoDB/整合\"}]},{\"text\":\"ElasticSearch\",\"collapsed\":true,\"items\":[{\"text\":\"ES基础\",\"link\":\"/2、数据库/ElasticSearch/1、ES基础\"},{\"text\":\"ES高级\",\"link\":\"/2、数据库/ElasticSearch/3、ES高级\"}]},{\"text\":\"InfluxDB\",\"link\":\"/2、数据库/influxdb\"},{\"text\":\"Neo4j\",\"link\":\"/2、数据库/Neo4j\"}]},{\"text\":\"高并发 & 秒杀 & 分布式\",\"collapsed\":true,\"items\":[{\"text\":\"分布式理论\",\"link\":\"/三高/分布式\"},{\"text\":\"分布式锁\",\"link\":\"/4、微服务/必备/分布式锁\"},{\"text\":\"秒杀\",\"link\":\"/三高/秒杀\"},{\"text\":\"高可用\",\"link\":\"/三高/高可用\"},{\"text\":\"高并发\",\"link\":\"/三高/高并发\"}]},{\"text\":\"云原生\",\"collapsed\":true,\"items\":[{\"text\":\"Docker\",\"link\":\"/云原生/Docker\"},{\"text\":\"K8S\",\"link\":\"/云原生/K8S\"}]},{\"text\":\"可视化 & 监控\",\"collapsed\":true,\"items\":[{\"text\":\"监控基础\",\"link\":\"/可视化 & 监控/监控基础\"},{\"text\":\"监控进阶\",\"link\":\"/可视化 & 监控/监控进阶\"},{\"text\":\"可视化大屏\",\"link\":\"/可视化 & 监控/可视化大屏\"},{\"text\":\"Zabbix\",\"link\":\"/可视化 & 监控/Zabbix\"}]},{\"text\":\"学前端\",\"collapsed\":true,\"items\":[{\"text\":\"HTML+CSS\",\"collapsed\":true,\"items\":[{\"text\":\"HTML基础\",\"link\":\"/1、学前端/1、HTML+CSS/HTML基础\"},{\"text\":\"CSS基础\",\"link\":\"/1、学前端/1、HTML+CSS/CSS基础\"},{\"text\":\"网页进阶\",\"link\":\"/1、学前端/1、HTML+CSS/网页进阶\"}]},{\"text\":\"JS+TS\",\"collapsed\":true,\"items\":[{\"text\":\"JS基础\",\"link\":\"/1、学前端/2、JS+TS/JS 基础\"},{\"text\":\"JS进阶\",\"link\":\"/1、学前端/2、JS+TS/JS 进阶\"},{\"text\":\"ES6基础\",\"link\":\"/1、学前端/2、JS+TS/ES6 基础\"},{\"text\":\"ES6进阶\",\"link\":\"/1、学前端/2、JS+TS/ES6 进阶\"},{\"text\":\"TS基础\",\"link\":\"/1、学前端/2、JS+TS/TypeScript\"}]},{\"text\":\"NodeJS\",\"collapsed\":true,\"items\":[{\"text\":\"Node基础\",\"link\":\"/1、学前端/4、Node/基础篇\"},{\"text\":\"Node进阶\",\"link\":\"/1、学前端/4、Node/进阶篇\"},{\"text\":\"项目实战\",\"link\":\"/1、学前端/4、Node/项目实战\"}]},{\"text\":\"Vue\",\"collapsed\":true,\"items\":[{\"text\":\"Vue3进阶\",\"link\":\"/1、学前端/3、Vue/Vue3/Vue3进阶\"},{\"text\":\"Vue3高级\",\"link\":\"/1、学前端/3、Vue/Vue3/Vue3高级\"},{\"text\":\"Vue3新语法\",\"link\":\"/1、学前端/3、Vue/Vue3/Vue3新语法\"},{\"text\":\"项目实战\",\"link\":\"/1、学前端/3、Vue/Vue2/Vue2项目\"}]},{\"text\":\"小程序\",\"collapsed\":true,\"items\":[{\"text\":\"小程序基础\",\"link\":\"/1、学前端/5、小程序/微信小程序\"},{\"text\":\"小程序优化\",\"link\":\"/1、学前端/5、小程序/小程序优化\"},{\"text\":\"uniapp\",\"link\":\"/1、学前端/5、小程序/uniapp\"},{\"text\":\"项目实战\",\"link\":\"/1、学前端/5、小程序/小程序项目\"}]}]},{\"text\":\"计算机基础\",\"collapsed\":true,\"items\":[{\"text\":\"数据结构\",\"link\":\"/计算机基础/数据结构/基础篇\"},{\"text\":\"操作系统\",\"link\":\"/计算机基础/计算机基础/操作系统\"},{\"text\":\"设计模式\",\"link\":\"/计算机基础/设计模式/基础篇\"},{\"text\":\"计算机网络\",\"link\":\"/计算机基础/计算机网络/网络基础\"},{\"text\":\"UML\",\"link\":\"/计算机基础/设计模式/UML\"},{\"text\":\"LeetCode\",\"link\":\"/计算机基础/算法/LeetCode\"}]},{\"text\":\"项目实战\",\"collapsed\":true,\"items\":[{\"text\":\"云尚办公\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/项目实战/云尚办公/基础篇\"}]},{\"text\":\"小兔鲜\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/项目实战/小兔鲜/基础篇\"},{\"text\":\"进阶篇1\",\"link\":\"/项目实战/小兔鲜/进阶篇1\"},{\"text\":\"进阶篇2\",\"link\":\"/项目实战/小兔鲜/进阶篇2\"}]},{\"text\":\"地图\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/项目实战/百度地图/基础篇\"},{\"text\":\"进阶篇\",\"link\":\"/项目实战/百度地图/进阶篇\"}]},{\"text\":\"苍穹外卖\",\"collapsed\":true,\"items\":[{\"text\":\"进阶篇\",\"link\":\"/项目实战/苍穹外卖/进阶篇\"}]},{\"text\":\"黑马头条\",\"collapsed\":true,\"items\":[{\"text\":\"基础篇\",\"link\":\"/项目实战/黑马头条/基础篇\"},{\"text\":\"进阶篇\",\"link\":\"/项目实战/黑马头条/进阶篇\"},{\"text\":\"进阶篇2\",\"link\":\"/项目实战/黑马头条/进阶篇2\"},{\"text\":\"高级篇\",\"link\":\"/项目实战/黑马头条/高级篇\"}]},{\"text\":\"支付\",\"link\":\"/项目实战/支付\"},{\"text\":\"项目推荐\",\"link\":\"/项目实战/项目推荐\"}]},{\"text\":\"团队成员\",\"link\":\"/team\"}],\"siteTitle\":\"任硕的文档\",\"logo\":\"/Vue.png\",\"nav\":[{\"text\":\"Java学前端\",\"items\":[{\"items\":[{\"text\":\"HTML+JS\",\"link\":\"/Java学前端/HTML+JS\"},{\"text\":\"CSS\",\"link\":\"/Java学前端/CSS\"},{\"text\":\"Vue2+组件\",\"link\":\"/Java学前端/Vue2+组件\"},{\"text\":\"Vue3+组件\",\"link\":\"/Java学前端/Vue3+组件\"},{\"text\":\"React\",\"link\":\"/Java学前端/React\"}]}],\"activeMatch\":\"/Java/\"},{\"text\":\"软件测试\",\"items\":[{\"items\":[{\"text\":\"测试基础\",\"link\":\"/软件测试/测试基础\"},{\"text\":\"压力测试\",\"link\":\"/软件测试/压力测试\"}]}]},{\"text\":\"多线程\",\"items\":[{\"items\":[{\"text\":\"基础篇\",\"link\":\"/并发 & 多线程/基础篇\"},{\"text\":\"进阶篇\",\"link\":\"/并发 & 多线程/并发完善\"}]}]},{\"text\":\"开发工具\",\"items\":[{\"items\":[{\"text\":\"Chrome\",\"link\":\"/IDEA/Chrome\"},{\"text\":\"IDEA基础\",\"link\":\"/IDEA/IDEA基础\"},{\"text\":\"IDEA插件\",\"link\":\"/IDEA/IDEA插件\"},{\"text\":\"VS Code\",\"link\":\"/IDEA/VS Code\"}]}]},{\"text\":\"消息中间件\",\"items\":[{\"items\":[{\"text\":\"RabbitMQ\",\"link\":\"/消息中间件/RabbitMQ\"},{\"text\":\"RocketMQ\",\"link\":\"/消息中间件/RocketMQ\"},{\"text\":\"Kafka\",\"link\":\"/消息中间件/Kafka\"},{\"text\":\"Canal\",\"link\":\"/消息中间件/Canal\"}]}]}],\"socialLinks\":[{\"icon\":\"github\",\"link\":\"https://github.com/renshuo123/renshuo123.github.io\"},{\"icon\":\"twitter\",\"link\":\"#\"},{\"icon\":{\"svg\":\"<svg t=\\\"1676028692954\\\" class=\\\"icon\\\" ...</path></svg>\"},\"link\":\"https://github.com/\"}]},\"locales\":{},\"scrollOffset\":90,\"cleanUrls\":false}");</script>
    
  </body>
</html>